本篇內(nèi)容主要講解“Express.js的原理及用法”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Express.js的原理及用法”吧!
成都創(chuàng)新互聯(lián)公司始終堅(jiān)持【策劃先行,效果至上】的經(jīng)營(yíng)理念,通過(guò)多達(dá)十余年累計(jì)超上千家客戶(hù)的網(wǎng)站建設(shè)總結(jié)了一套系統(tǒng)有效的全網(wǎng)營(yíng)銷(xiāo)推廣解決方案,現(xiàn)已廣泛運(yùn)用于各行各業(yè)的客戶(hù),其中包括:成都服務(wù)器租用等企業(yè),備受客戶(hù)稱(chēng)贊。
本文針對(duì)那些對(duì)Node.js有一定了解的讀者。假設(shè)你已經(jīng)知道如何運(yùn)行Node代碼,使用npm安裝依賴(lài)模塊。但我保證,你并不需要是這方面的專(zhuān)家。本文針對(duì)的是Express 3.2.5版本,以介紹相關(guān)概念為主。
Express.js這么描述自己:”輕量靈活的Node.js Web應(yīng)用框架”。它可以幫助你快速搭建web應(yīng)用。如果你使用過(guò)Ruby里的Sinatra,那么相信你對(duì)這個(gè)也會(huì)很快就能熟悉。
和其他web框架一樣,Express隱藏了代碼背后的祕(mì)密,然后告訴你:”別擔(dān)心,你不用去理解這個(gè)部分”。它來(lái)幫你解決這些問(wèn)題,所以你不用去為這個(gè)而煩惱,只用將重心集中到代碼上。換句話(huà)說(shuō),它有某些魔法!
Express的wiki里介紹了一些它的使用者,其中就有很多知名的公司: MySpace, Klout.
但是擁有魔力是需要付出代價(jià)的,你可能根本就不知道它的工作原理。正如駕駛一輛汽車(chē),我可以很好的駕馭它但是可能不理解為什么汽車(chē)可以正常工作,但是我最好知道這些東西。如果車(chē)壞掉怎么辦?如果你想最大程度的去發(fā)揮它的性能?如果你對(duì)知識(shí)有無(wú)限的渴望并想去弄清它?
那么我首先從理解Express的最底層-Node開(kāi)始。
底層:Node HTTP服務(wù)器
Node中有HTTP模塊, 它將搭建一個(gè)web服務(wù)器的過(guò)程抽象出來(lái)。你可以這樣使用:
// 引入所需模塊 var http = require("http"); // 建立服務(wù)器 var app = http.createServer(function(request, response) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Hello world!\n"); }); // 啟動(dòng)服務(wù)器 app.listen(1337, "localhost"); console.log("Server running at http://localhost:1337/");
運(yùn)行這個(gè)程序(假設(shè)文件名為 app.js
,運(yùn)行 node app.js
),你會(huì)得到”Hello world!“ 在瀏覽器訪(fǎng)問(wèn)localhost:1337
,你會(huì)得到同樣的結(jié)果。你也可以嘗試訪(fǎng)問(wèn)其他地址,如 localhost:1337/whatever
,結(jié)果仍然會(huì)一樣。
分解以上代碼來(lái)看。
第一行使用 require
函數(shù)引入Node內(nèi)置模塊 http
。然后存入名為 http
的變量中。如果你要了解更多關(guān)于require函數(shù)的知識(shí),參考Nodejitsu的文檔。
然后我們使用 http.createServer
將服務(wù)器保存至 app
變量。它將一個(gè)函數(shù)作為參數(shù)監(jiān)聽(tīng)請(qǐng)求。稍后將會(huì)詳細(xì)介紹它。
最后我們要做的就是告訴服務(wù)器監(jiān)聽(tīng)來(lái)自1337端口的請(qǐng)求,之后輸出結(jié)果。然后一切完成。
好的,回到request請(qǐng)求處理函數(shù)。這個(gè)函數(shù)相當(dāng)重要。
request方法
在開(kāi)始這個(gè)部分之前,我事先聲明這里所涉及的HTTP相關(guān)知識(shí)與學(xué)習(xí)Express本身沒(méi)有太大關(guān)係。如果你感興趣,可以查看HTTP模塊文檔。
任何時(shí)候我們向服務(wù)器發(fā)起請(qǐng)求,request方法將會(huì)被調(diào)用。如果你不信,你可以 console.log
將結(jié)果打印出來(lái)。你會(huì)發(fā)現(xiàn)每次請(qǐng)求一個(gè)頁(yè)面時(shí)它都會(huì)出來(lái)。
request
是來(lái)自客戶(hù)端的請(qǐng)求。在很多應(yīng)用中,你可能會(huì)看到它的縮寫(xiě) req
。仔細(xì)看代碼。我們修改代碼如下:
var app = http.createServer(function(request, response) { // 創(chuàng)建answer變量 var answer = ""; answer += "Request URL: " + request.url + "\n"; answer += "Request type: " + request.method + "\n"; answer += "Request headers: " + JSON.stringify(request.headers) + "\n"; // 返回結(jié)果 response.writeHead(200, {"Content-Type": "text/plain" }); response.end(answer); });
重啟服務(wù)器并刷新 localhsot:1337
.你會(huì)發(fā)現(xiàn),每次訪(fǎng)問(wèn)一個(gè)URL,就會(huì)發(fā)起一次GET請(qǐng)求,并會(huì)得到一堆類(lèi)似用戶(hù)代理或者一些其他的更加複雜的HTTP相關(guān)信息。如果你訪(fǎng)問(wèn) localhost:1337/what_is_fraser
, 你會(huì)看到request的地址發(fā)生了變化。如果你使用不同的瀏覽器訪(fǎng)問(wèn),用戶(hù)代理也會(huì)跟著改變,如果你使用POST請(qǐng)求,request的方法也很改變。
response
是另外一個(gè)部分。正如 request
被縮寫(xiě)為 req
,response
同樣被簡(jiǎn)寫(xiě)為 res
。每次response你都會(huì)得到對(duì)應(yīng)的返回結(jié)果,之后你便可以通過(guò)調(diào)用 response.end
來(lái)結(jié)束。實(shí)際上最終你還是要執(zhí)行這個(gè)方法的, 甚至在node的文檔里也是這么描述的。這個(gè)方法完成了真正的數(shù)據(jù)傳輸部分。你可以建立一個(gè)服務(wù)器并不調(diào)用 req.end
方法,它就會(huì)永遠(yuǎn)存在。
在你返回結(jié)果之前,你也可以填寫(xiě)一下header頭部部分。我們的例子里是這么寫(xiě)的:
response.writeHead(200, { "Content-Type": "text/plain" });
這個(gè)步驟主要完成兩件事情。第一,發(fā)送HTTP狀態(tài)碼,表示請(qǐng)求成功。其次,它設(shè)置了返回的頭部信息。這里表示我們要返回的是純文本格式的內(nèi)容。我們也可以返回類(lèi)似JSON或者HTML格式的內(nèi)容。
未完待續(xù)。。。
// 接上回
看了上面的之后,你可能會(huì)立馬開(kāi)始利用它來(lái)寫(xiě)api了。
var http = require("http"); http.createServer(function(req, res) { // Homepage if(req.url == "/") { res.writeHead(200, { "Content-Type": "text/html" }); res.end("Welcome to the homepage!"); } // About page else if (req.url == "/about") { res.writeHead(200, { "Content-Type": "text/html" }); res.end("Welcome to the about page!"); } // 404'd! else { res.writeHead(404, { "Content-Type": "text/plain" }); res.end("404 error! File not found."); } }).listen(1337, "localhost");
你可以選擇優(yōu)化代碼,讓它變得更整潔。也可以向npm.org的那幫傢伙一樣用原生的Node來(lái)編寫(xiě)。但是你也可以選擇去創(chuàng)建一個(gè)框架。這就是Sencha所做的,并把這個(gè)框架稱(chēng)為 – Connect.
中間件: Connect
Connect是Nodejs的中間件??赡苣悻F(xiàn)在還并不太理解什么是中間件(middleware),別擔(dān)心,我馬上會(huì)進(jìn)行詳細(xì)解釋。
一段Connect代碼
假如我們想要編寫(xiě)和上面一樣的代碼,但是這次我們要使用Connect.別忘記安裝Connect模塊(npm install
)。完成之后,代碼看起來(lái)非常相似。
// 引入所需模塊 var connect = require("connect"); var http = require("http"); // 建立app var app = connect(); // 添加中間件 app.use(function(request, response) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Hello world!\n"); }); // 啟動(dòng)應(yīng)用 http.createServer(app).listen(1337);
下面分解這段代碼來(lái)看。
首先我們分別引入了Connect和Node HTTP模塊。
接下來(lái)和之前一樣聲明 app
變量,但是在創(chuàng)建服務(wù)器時(shí),我們調(diào)用了 connect()
.這有是如何工作的?
我們添加了一個(gè)中間件,實(shí)際上就是一個(gè)函數(shù)。傳入 app.use
,幾乎和上面使用request方法寫(xiě)法一樣。實(shí)際上代碼是從上面粘貼過(guò)來(lái)的。
之后我們建立并啓動(dòng)服務(wù)器。 http.createServer
接收函數(shù)作為參數(shù)。沒(méi)錯(cuò),app
實(shí)際上也是一個(gè)函數(shù)。這是一個(gè)Connect提供的函數(shù),它會(huì)查找代碼并自上而下執(zhí)行。
(你可能會(huì)看見(jiàn)其他人使用 app.listen(1337)
, 這實(shí)際上只是將 http.createServer
返回一個(gè)promise對(duì)象。 再Connect和Express中都是一樣的原理。)
接下來(lái)解釋什么是中間件(middleware).
什么是中間件?
首先推薦閱讀Stephen Sugden對(duì)于Connect中間件的描述,比我講的更好。如果你不喜歡我的解釋?zhuān)蔷腿タ纯础?/p>
還記得之前的request方法?每個(gè)中間件都是一個(gè)handler.依次傳入request, response, next三個(gè)參數(shù)。
一個(gè)最基本的中間件結(jié)構(gòu)如下:
function myFunMiddleware(request, response, next) { // 對(duì)request和response作出相應(yīng)操作 // 操作完畢后返回next()即可轉(zhuǎn)入下個(gè)中間件 next(); }
當(dāng)我們啓動(dòng)一個(gè)服務(wù)器,函數(shù)開(kāi)始從頂部一直往下執(zhí)行。如果你想輸出函數(shù)的執(zhí)行過(guò)程,添加一下代碼:
var connect = require("connect"); var http = require("http"); var app = connect(); // log中間件 app.use(function(request, response, next) { console.log("In comes a " + request.method + " to " + request.url); next(); }); // 返回"hello world" app.use(function(request, response, next) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Hello World!\n"); }); http.createServer(app).listen(1337);
如果你啓動(dòng)應(yīng)用并訪(fǎng)問(wèn) localhost:1337
,你會(huì)看到服務(wù)器可以log出相關(guān)信息。
有一點(diǎn)值得注意,任何可以在Node.js下執(zhí)行的代碼都可以在中間件執(zhí)行。例如上面我們所使用的req.method
方法。
你當(dāng)然可以編寫(xiě)自己的中間件,但是也不要錯(cuò)過(guò)Connect的一些很cool的第三方中間件。下面我們移除自己的log中間件,使用Connect內(nèi)置方法。
var connect = require("connect"); var http = require("http"); var app = connect(); app.use(connect.logger()); // 一個(gè)有趣的事實(shí):connect.logger返回一個(gè)函數(shù) app.use(function(request, response) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Hello world!\n"); }); http.createServer(app).listen(1337);
跳轉(zhuǎn)至瀏覽器并訪(fǎng)問(wèn) localhost:1337
你會(huì)得到同樣的結(jié)果。
很快有人就會(huì)想使用上面的中間件組合起來(lái)創(chuàng)建一個(gè)完整應(yīng)用。代碼如下:
var connect = require("connect"); var http = require("http"); var app = connect(); app.use(connect.logger()); // Homepage app.use(function(request, response, next) { if (request.url == "/") { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Welcome to the homepage!\n"); // The middleware stops here. } else { next(); } }); // About page app.use(function(request, response, next) { if (request.url == "/about") { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Welcome to the about page!\n"); // The middleware stops here. } else { next(); } }); // 404'd! app.use(function(request, response) { response.writeHead(404, { "Content-Type": "text/plain" }); response.end("404 error!\n"); }); http.createServer(app).listen(1337);
“這個(gè)看起來(lái)不太好看!我要自己寫(xiě)框架!”
某些人看了Connect的代碼之后覺(jué)得,“這個(gè)代碼可以更簡(jiǎn)單”。于是他們創(chuàng)造了Express.(事實(shí)上他們好像直接盜用了Sinatra.)
最頂層: Express
文章進(jìn)入第三部分,我們開(kāi)始真正進(jìn)入Express.
正如Connect拓展了Node, Express拓展Connect.代碼的開(kāi)始部分看起來(lái)和在Connect中非常類(lèi)似:
var express = require("express"); var http = require("http"); var app = express();
結(jié)尾部分也一樣:
http.createServer(app).listen(1337);
中間部分纔是不一樣的地方。Connect為我們提供了中間件,Express則為我們提供了另外三個(gè)優(yōu)秀的特性: 路由分發(fā),請(qǐng)求處理,視圖渲染。首先從如有開(kāi)始看。
特性一:路由
路由的功能就是處理不同的請(qǐng)求。在上面的很多例子中,我們分別有首頁(yè),關(guān)于和404頁(yè)面。我們是通過(guò) if
來(lái)判斷并處理不同請(qǐng)求地址。
但是Express卻可以做的更好。Express提供了”routing”這個(gè)東西,也就是我們所說(shuō)的路由。我覺(jué)得可讀性甚至比純文字還要好。
var express = require("express"); var http = require("http"); var app = express(); app.all("*", function(request, response, next) { response.writeHead(404, { "Content-Type": "text/plain" }); next(); }); app.get("/", function(request, response) { response.end("Welcome to the homepage!"); }); app.get("/about", function(request, response) { response.end("Welcome to the about page!"); }); app.get("*", function(request, response) { response.end("404!"); }); http.createServer(app).listen(1337);
簡(jiǎn)單的引入相關(guān)模塊之后,我們立即調(diào)用 app.all
處理所有請(qǐng)求。寫(xiě)法看起來(lái)也非常像中間件不是嗎?
代碼中的 app.get
就是Express提供的路由系統(tǒng)。也可以是 app.post
來(lái)處理POST請(qǐng)求,或者是PUT和任何的HTTP請(qǐng)求方式。第一個(gè)參數(shù)是路徑,例如 /about
或者 /
。第二個(gè)參數(shù)類(lèi)似我們之前所見(jiàn)過(guò)的請(qǐng)求handler。引用Expess文檔的內(nèi)容:
這些請(qǐng)求handler和中間件一樣,唯一的區(qū)別是這些回調(diào)函數(shù)會(huì)調(diào)用
next('route')
從而能夠繼續(xù)執(zhí)行剩下的路由回調(diào)函數(shù)。這種機(jī)制
簡(jiǎn)單說(shuō)來(lái),它們和我們之前提過(guò)的中間件是一樣,只不過(guò)是一些函數(shù)而已。
這些路由也可以更加靈活,看起來(lái)是這樣:
app.get("/hello/:who", function(req, res) { res.end("Hello, " + req.params.who + "."); });
重啟服務(wù)器并在瀏覽器訪(fǎng)問(wèn) localhost:1337/hello/animelover69
你會(huì)得到如下信息:
<code>Hello, animelover69. </code>
這些文檔演示了如何使用正則表達(dá)式,可以使得路由更加靈活。如果只是單從概念理解來(lái)講,我說(shuō)的已經(jīng)足夠了。
但是還有更加值得我們?nèi)リP(guān)注的。
特性二:請(qǐng)求處理 request handling
Express將你傳入請(qǐng)求的handler傳入request和response對(duì)象中。原先該有的還在,但是卻加入了更多新的特性。API文檔里有詳細(xì)解釋。下面讓我們來(lái)看一些例子。
其中一個(gè)就是 redirect
方法。代碼如下:
response.redirect("/hello/anime"); response.redirect("http://xvfeng.me"); response.redirect(301, "http://xvfeng.me"); // HTTP 301狀態(tài)碼
以上代碼既不屬于原生Node代碼也不是來(lái)自與Connect,而是Express中自身添加的。它加入了一些例如sendFile
,讓你傳輸整個(gè)文件等功能:
response.sendFile("/path/to/anime.mp4");
request對(duì)象還有一些很cool的屬性,例如 request.ip
可以獲取IP地址, request.files
上傳文件等。
理論上來(lái)講,我們要知道的東西也不是太多,Express做的只是拓展了request和response對(duì)象而已。Express所提供的方法,請(qǐng)參考API文檔.
特性三:視圖
Express可以渲染視圖。代碼如下:
// 啟動(dòng)Express var express = require("express"); var app = express(); // 設(shè)置view目錄 app.set("views", __dirname + "/views"); // 設(shè)置模板引擎 app.set("view engine", "jade");
開(kāi)頭部分的代碼和前面基本一樣。之后我們指定視圖文件所在目錄。然后告訴Express我們要使用 Jade
作為模板引擎。 Jade是一種模板語(yǔ)言。稍后將會(huì)詳細(xì)介紹。
現(xiàn)在我們已經(jīng)設(shè)置好了view.但是如何來(lái)使用它呢?
首先我們建立一個(gè)名為 index.jade
的文件并把它放入 views
目錄。代碼如下:
doctype 5 html body h2 Hello, world! p= message
代碼只是去掉了括號(hào)的HTML代碼。如果你懂HTML那肯定也看得懂上面的代碼。唯一有趣的是最后一樣。 message
是一個(gè)變量。它是從哪里來(lái)的呢?馬上告訴你。
我們需要從Express中渲染這個(gè)視圖。代碼如下:
app.get("/", function(request, response) { response.render("index", { message: "I love anime" }); });
Express為 response
對(duì)象添加了一個(gè) render
方法。這個(gè)方法可以處理很多事情,但最主要的還是加載模板引擎和對(duì)應(yīng)的視圖文件,之后渲染成普通的HTML文檔,例如這里的 index.jade
.
最后一步(我覺(jué)得可能算是第一步)就是安裝Jade,因?yàn)樗旧聿⒉皇荅xpress的一部分。添加至package.json
文件并使用 npm install
進(jìn)行安裝。
如果一起設(shè)置完畢,你會(huì)看到這個(gè)頁(yè)面。完整代碼.
加分特性: 所有代碼來(lái)自于Connect和Node
我需要再次提醒你的是Express建立與Connect和Node之上,這意味著所有的Connect中間件均可以在Express中使用。這個(gè)對(duì)與開(kāi)發(fā)來(lái)講幫助很大。例如:
var express = require("express"); var app = express(); app.use(express.logger()); // 繼承自Connect app.get("/", function(req, res) { res.send("fraser"); }); app.listen(1337);
如果說(shuō)你從這篇文章中學(xué)到了一點(diǎn)什么,就是這一點(diǎn)。
實(shí)戰(zhàn)
本文的大部分內(nèi)容都是理論,但是下面我將教你如何使用它來(lái)做一點(diǎn)你想做的東西。我不想說(shuō)的過(guò)于具體。
你可以將Express安裝到系統(tǒng)全局,從而可以在命令行使用它。它可以幫助你迅速的完成代碼組織并啓動(dòng)應(yīng)用。使用npm安裝:
<code># 安裝時(shí)可能需要加 `sudo` npm install -g express </code>
如果你需要幫助,輸入 express --help
。它加入一些可選參數(shù)。例如,如果你想使用EJS模板引擎,LESS作為CSS引擎。應(yīng)用的名稱(chēng)為”myApp”.輸入以下命令:
<code>express --ejs --css less myApp </code>
這里會(huì)自動(dòng)生成很多文件。進(jìn)入項(xiàng)目目錄,并使用 npm install
安裝依賴(lài)包,之后便可以使用 node app
啓動(dòng)應(yīng)用!我建議你詳細(xì)的查看項(xiàng)目結(jié)構(gòu)和代碼。它可能還算不上一個(gè)真正的應(yīng)用,但是我覺(jué)得它對(duì)于初學(xué)者來(lái)講還是很有幫助的。
項(xiàng)目Github目錄下也有一些很有幫助的文檔。
一些補(bǔ)充
如果你也和我一樣喜歡使用CoffeeScript,好消息是Express完美支持CoffeeScript.你甚至不需要編譯它。這樣你只用 coffee app.coffee
即可啓動(dòng)應(yīng)用。我在我的其他項(xiàng)目中也是這么做的。
在我看到 app.use(app.router)
的時(shí)候我很疑惑: Express不是一直在使用router嗎?簡(jiǎn)單回答是app.router
是Express的路由中間件,在你定義路由的時(shí)候被直接添加到項(xiàng)目中。如果你需要在加載其他文件之前應(yīng)用,也可以直接引入它。關(guān)于這么做的原因,請(qǐng)參考StackOverflow的這個(gè)答桉.
本文是針對(duì)Express 3,而在第四版的規(guī)劃中又會(huì)有很多大的改動(dòng)。最明顯的是,Experss可能要將會(huì)分解成一些小的模塊,并吸收Connect的一些特性。這個(gè)雖然還在計(jì)劃中,但是也值得一看。
如果這個(gè)還不能滿(mǎn)足你?你肯定是個(gè)變態(tài)!你很快就會(huì)變成像一個(gè)癮君子,半睜著眼,耗盡你最后一點(diǎn)精力,寫(xiě)著苦逼的代碼。
正如Rails成為使用Ruby建立網(wǎng)頁(yè)應(yīng)用的王者一樣,我覺(jué)得Express也會(huì)成為Node中的主流。但是和Rails不一樣,Express 更加底層。似乎還沒(méi)有一個(gè)真正意義上的高級(jí)Node庫(kù)。我覺(jué)得可能會(huì)發(fā)生改變。(譯者注:這點(diǎn)我不同意,Node的很多思想來(lái)自與Unix哲學(xué),強(qiáng)調(diào)的是一個(gè)Module只解決一個(gè)問(wèn)題,而不是成為一個(gè)複雜的庫(kù)。很多Rails的開(kāi)發(fā)者轉(zhuǎn)向Node,就是因?yàn)镽ails正在逐漸變得臃腫,不易自定義,且效率逐漸降低。)。
這里我就不再多談。已經(jīng)又很多很基于Express建立了新的東西,Expess的維基里有列舉。如果你覺(jué)得好可以隨意使用它們,如果你喜歡從底層做起,你也可以只選擇Express。不管是哪一種,好好利用它吧。
到此,相信大家對(duì)“Express.js的原理及用法”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!
分享標(biāo)題:Express.js的原理及用法
本文來(lái)源:http://jinyejixie.com/article20/jdojjo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶(hù)體驗(yàn)、手機(jī)網(wǎng)站建設(shè)、面包屑導(dǎo)航、軟件開(kāi)發(fā)、靜態(tài)網(wǎng)站、網(wǎng)站維護(hù)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)