1、介紹Express.js無(wú)疑是當(dāng)前Node.js中最流行的Web應(yīng)用程序框架。它幾乎成為了大多數(shù)Node.js web應(yīng)用程序的基本的依賴(lài),甚至一些例如Sails.js這樣的流行的框架也是基于Express.js。然而你還有一些其他框架的選擇,可以給你帶來(lái)“sinatra”一樣的感覺(jué)(譯注:sinatra是一個(gè)簡(jiǎn)單的Ruby的Web框架,可以參考這篇博文)。另外兩個(gè)最流行的框架分別是Koa和Hapi。 這篇文章不是打算說(shuō)服你哪個(gè)框架比另外一個(gè)更好,而是只是打算讓你更好地理解每個(gè)框架能做什么,什么情況下一個(gè)框架可以秒殺另外一個(gè)。 2、框架的背景我們將要探討的兩個(gè)框架看起來(lái)都非常相似。每一個(gè)都能夠用幾行代碼來(lái)構(gòu)建一個(gè)服務(wù)器,并都可以非常輕易地構(gòu)建REST API。我們先瞧瞧這幾個(gè)框架是怎么誕生的。 2.1 Express2009年6月26日,TJ Holowaychuk提交了Express的第一次commit,接下來(lái)在2010年1月2日,有660次commits的Express 0.0.1版本正式發(fā)布。TJ和Ciaron Jessup是當(dāng)時(shí)最主要的兩個(gè)代碼貢獻(xiàn)者。在第一個(gè)版本發(fā)布的時(shí)候,根據(jù)github上的readme.md,這個(gè)框架被描述成:
差不多5年的時(shí)間過(guò)去了,Express擁有了4,925次commit,現(xiàn)在Express的最新版本是4.10.1,由StrongLoop維護(hù),因?yàn)門(mén)J現(xiàn)在已經(jīng)跑去玩Go了。 2.2 Koa大概在差不多一年前的2013年8月17日,TJ Holowaychuk(又是他!)只身一人提交了Koa的第一次commit。他描述Koa為“表現(xiàn)力強(qiáng)勁的Node.js中間件,通過(guò)co使用generators使得編寫(xiě)web應(yīng)用程序和REST API更加絲般順滑”。Koa被標(biāo)榜為只占用約400行源碼空間的框架。Koa的目前最新版本為0.13.0,擁有583次commits。 2.3 Hapi2011年8月5日,WalmartLabs的一位成員Eran Hammer提交了Hapi的第一次commit。Hapi原本是Postmile的一部分,并且最開(kāi)始是基于Express構(gòu)建的。后來(lái)它發(fā)展成自己自己的框架,正如Eran在他的博客里面所說(shuō)的:
Hapi最新版本為7.2.0,擁有3,816次commits,并且仍然由Eran Hammer維護(hù)。 所有開(kāi)發(fā)者要開(kāi)發(fā)Node.js web應(yīng)用程序的第一步就是構(gòu)建一個(gè)基本的服務(wù)器。所以我們來(lái)看看用這幾個(gè)框架構(gòu)建一個(gè)服務(wù)器的時(shí)候有什么異同。 3 創(chuàng)建一個(gè)服務(wù)器所有開(kāi)發(fā)者要開(kāi)發(fā)Node.js web應(yīng)用程序的第一步就是構(gòu)建一個(gè)基本的服務(wù)器。所以我們來(lái)看看用這幾個(gè)框架構(gòu)建一個(gè)服務(wù)器的時(shí)候有什么異同。 3.1 Express
對(duì)于所有的node開(kāi)發(fā)者來(lái)說(shuō),這看起來(lái)相當(dāng)?shù)淖匀弧N覀儼裡xpress require進(jìn)來(lái),然后初始化一個(gè)實(shí)例并且賦值給一個(gè)為app的變量。接下來(lái)這個(gè)實(shí)例初始化一個(gè)server監(jiān)聽(tīng)特定的端口,3000端口。app.listen()函數(shù)實(shí)際上包裝了node原生的http.createServer()函數(shù)。 3.2 Koa
你馬上發(fā)現(xiàn)Koa和Express是很相似的。其實(shí)差別只是你把require那部分換成koa而不是express而已。app.listen()也是和Express一模一樣的對(duì)原生代碼的封裝函數(shù)。 3.3 Hapi
Hapi是三者中最獨(dú)特的一個(gè)。和其他兩者一樣,hapi被require進(jìn)來(lái)了但是沒(méi)有初始化一個(gè)hapi app而是構(gòu)建了一個(gè)server并且指定了端口。在Express和Koa中我們得到的是一個(gè)回調(diào)函數(shù)而在hapi中我們得到的是一個(gè)新的server對(duì)象。一旦我們調(diào)用了server.start()我們就開(kāi)啟了端口為3000的服務(wù)器,并且返回一個(gè)回調(diào)函數(shù)。這個(gè)server.start()函數(shù)和Koa、Express不一樣,它并不是一個(gè)http.CreateServer()的包裝函數(shù),它的邏輯是由自己構(gòu)建的。 4 路由控制現(xiàn)在一起來(lái)搞搞一下服務(wù)器最重要的特定之一,路由控制。我們先用每個(gè)框架分別構(gòu)建一個(gè)老掉渣的“Hello world”應(yīng)用程序,然后我們?cè)偬剿饕幌乱恍└杏玫臇|東,REST API。 4.1 Hello world4.1.1 Express
我們用get()函數(shù)來(lái)捕獲“GET /”請(qǐng)求然后調(diào)用一個(gè)回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)會(huì)被傳入req和res兩個(gè)對(duì)象。這個(gè)例子當(dāng)中我們只利用了res的res.send()來(lái)返回整個(gè)頁(yè)面的字符串。Express有很多內(nèi)置的方法可以用來(lái)進(jìn)行路由控制。get, post, put, head, delete等等這些方法都是Express支持的最常用的方法(這只是一部分而已,并不是全部)。 4.1.2 Koa
Koa和Express稍微有點(diǎn)兒不同,它用了ES6的generators。所有帶有*前綴的函數(shù)都表示這個(gè)函數(shù)會(huì)返回一個(gè)generator對(duì)象。根本上來(lái)說(shuō),generator會(huì)同步地yield出數(shù)據(jù)(譯注:如果對(duì)Python比較熟悉的話(huà),應(yīng)該對(duì)ES6的generator不陌生,這里的yield其實(shí)和Python的yield語(yǔ)句差不多一個(gè)意思),這個(gè)超出本文所探索的內(nèi)容,不詳述。在app.use()函數(shù)中,generator函數(shù)設(shè)置響應(yīng)體。在Koa中,this這個(gè)上下文其實(shí)就是對(duì)node的request和response對(duì)象的封裝。this.body是KoaResponse對(duì)象的一個(gè)屬性。this.body可以設(shè)置為字符串, buffer, stream, 對(duì)象, 或者null也行。上面的例子中我們使用了Koa為數(shù)不多的中間件的其中一個(gè)。這個(gè)中間件捕獲了所有的路由并且響應(yīng)同一個(gè)字符串。 4.1.3 Hapi
這里使用了server對(duì)象給我們提供的server.route內(nèi)置的方法,這個(gè)方法接受配置參數(shù):path(必須),method(必須),vhost,和handler(必須)。HTTP方法可以處理典型的例如GET、PUT、POST、DELETE的請(qǐng)求,*通配符可以匹配所有的路由。handler函數(shù)被傳入一個(gè)request對(duì)象的引用,它必須調(diào)用reply函數(shù)包含需要返回的數(shù)據(jù)。數(shù)據(jù)可以是字符串、buffer、可序列化對(duì)象、或者stream。 4.2 REST APIHello world除了給我們展示了如何讓一個(gè)應(yīng)用程序運(yùn)行起來(lái)以外幾乎啥都沒(méi)干。在所有的重?cái)?shù)據(jù)的應(yīng)用程序當(dāng)中,REST API幾乎是一個(gè)必須的設(shè)計(jì),并且能讓我們更好地理解這些框架是可以如何使用的?,F(xiàn)在讓我們看看這些框架是怎么處理REST API的。 4.2.1 Express
4.2.1 Express
我們?yōu)橐延械腍ello World應(yīng)用程序添加REST API。Express提供一些處理路由的便捷的方式。這是Express 4.x的語(yǔ)法,除了你不需要express.Router()和不能用app.user(‘/api’, router)以外,其實(shí)上是和Express 3.x本質(zhì)上是一樣的。在Express 3.x中,你需要用app.route()替換router.route()并且需要加上/api前綴。Express 4.x的這種語(yǔ)法可以減少開(kāi)發(fā)者編碼錯(cuò)誤并且你只需要修改少量代碼就可以修改HTTP方法規(guī)則。 4.2.2 Koa
很明顯,Koa并沒(méi)有類(lèi)似Express這樣的可以減少編碼重復(fù)路由規(guī)則的能力。它需要額外的中間件來(lái)處理路由控制。我選擇使用koa-route因?yàn)樗怯蒏oa團(tuán)隊(duì)維護(hù)的,但是還有很多由其他開(kāi)發(fā)者維護(hù)的可用的中間件。Koa的路由和Express一樣使用類(lèi)似的關(guān)鍵詞來(lái)定義它們的方法,.get(), .put(),.post(), 和 .delete()。Koa在處理路由的時(shí)候有一個(gè)好處就是,它使用ES6的generators函數(shù)來(lái)減少對(duì)回調(diào)函數(shù)的處理。 4.2.3 Hapi
對(duì)于Hapi路由處理的第一印象就是,相對(duì)于其它兩個(gè)框架,這貨是多么的清爽,可讀性是多么的棒!即使是那些必須的method,path,handler和reply配置參數(shù)都是那么的賞心悅目(譯注:作者高潮了)。類(lèi)似于Koa,Hapi很多重復(fù)的代碼會(huì)導(dǎo)致更大的出錯(cuò)多可能性。然而這是Hapi的有意之為,Hapi更關(guān)注配置并且希望使得代碼更加清晰和讓團(tuán)隊(duì)開(kāi)發(fā)使用起來(lái)更加簡(jiǎn)便。Hapi希望可以不需要開(kāi)發(fā)者進(jìn)行編碼的情況下對(duì)錯(cuò)誤處理進(jìn)行優(yōu)化。如果你嘗試去訪問(wèn)一個(gè)沒(méi)有被定義的REST API,它會(huì)返回一個(gè)包含狀態(tài)碼和錯(cuò)誤的描述的JSON對(duì)象。 5 優(yōu)缺點(diǎn)比較5.1 Express5.1.1 優(yōu)點(diǎn)Express擁有的社區(qū)不僅僅是上面三者當(dāng)中最大的,并且是所有Node.js web應(yīng)用程序框架當(dāng)中最大的。在經(jīng)過(guò)其背后差不多5年的發(fā)展和在StrongLoop的掌管下,它是三者當(dāng)中最成熟的框架。它為服務(wù)器啟動(dòng)和運(yùn)行提供了簡(jiǎn)單的方式,并且通過(guò)內(nèi)置的路由提高了代碼的復(fù)用性。 5.1.2 缺點(diǎn)使用Express需要手動(dòng)處理很多單調(diào)乏味的任務(wù)。它沒(méi)有內(nèi)置的錯(cuò)誤處理。當(dāng)你需要解決某個(gè)特定的問(wèn)題的時(shí)候,你會(huì)容易迷失在眾多可以添加的中間件中,在Express中,你有太多方式去解決同一個(gè)問(wèn)題。Express自詡為高度可配置,這有好處也有壞處,對(duì)于準(zhǔn)備使用Express的剛?cè)腴T(mén)的開(kāi)發(fā)者來(lái)說(shuō),這不是一件好的事情。并且對(duì)比起其他框架來(lái)說(shuō),Express體積更大。 5.2 Koa5.2.1 優(yōu)點(diǎn)Koa有著傲人的身材(體積小),它表現(xiàn)力更強(qiáng);對(duì)比起其他框架,它使得中間件的編寫(xiě)變的更加容易。Koa基本上就是一個(gè)只有骨架的框架,你可以選擇(或者自己寫(xiě)一個(gè))中間件,而不用妥協(xié)于Express或者Hapi它們自帶的中間件。它也是唯一一個(gè)采用ES6的框架,例如它使用了ES6的generators。 5.2.2 缺點(diǎn)Koa不穩(wěn)定,仍處于活躍的開(kāi)發(fā)完善階段。使用ES6還是有點(diǎn)太超前了,例如只有0.11.9+的Node.js版本才能運(yùn)行Koa,而現(xiàn)在最新的Node.js穩(wěn)定版本是0.10.33。和Express一樣有好也有壞的一點(diǎn)就是,在多種中間件的選擇還是自己寫(xiě)中間件。就像我們之前所用的router那樣,有太多類(lèi)似的router中間件可供我們選擇。 5.3 Hapi5.3.1 優(yōu)點(diǎn)Hapi自豪地宣稱(chēng)它自己是基于配置優(yōu)于編碼的概念,并且很多開(kāi)發(fā)者認(rèn)為這是一件好事。在團(tuán)隊(duì)項(xiàng)目開(kāi)發(fā)中,可以很容易地增強(qiáng)一致性和可復(fù)用性。作為有著大名鼎鼎的WalmartLabs支持的框架和其他響當(dāng)當(dāng)?shù)钠髽I(yè)在實(shí)際生產(chǎn)中使用Hapi,它已經(jīng)經(jīng)過(guò)了實(shí)際戰(zhàn)場(chǎng)的洗禮,企業(yè)們可以沒(méi)有擔(dān)憂(yōu)地基于Hopi運(yùn)行自己的應(yīng)用程序。所有的跡象都表明Hapi向著成為的偉大的框架的方向持續(xù)成熟。 5.3.2 缺點(diǎn)Hapi絕逼適合用來(lái)開(kāi)發(fā)更大更復(fù)雜的應(yīng)用。但對(duì)于一個(gè)簡(jiǎn)單的web app來(lái)說(shuō),它的可能有點(diǎn)兒堆砌太多樣板代碼了。而且Hapi的可供參考樣例太少了,或者說(shuō)開(kāi)源的使用Hapi的應(yīng)用程序太少了。所以選擇它對(duì)開(kāi)發(fā)者的要求更高一點(diǎn),而不是所使用的中間件。 6 總結(jié)我們已經(jīng)看過(guò)三個(gè)框架一些棒棒的而且很實(shí)際的例子了。Express毫無(wú)疑問(wèn)是三個(gè)當(dāng)中最流行和最出名的框架。當(dāng)你要開(kāi)發(fā)一個(gè)新的應(yīng)用程序的時(shí)候,使用Express來(lái)構(gòu)建一個(gè)服務(wù)器可能已經(jīng)成為了你的條件反射了;但希望現(xiàn)在你在做選擇的時(shí)候會(huì)多一些思考,可以考慮選擇Koa或者Hapi。Koa通過(guò)超前擁抱ES6和Web component的思想,顯示了Web開(kāi)發(fā)社區(qū)正在進(jìn)步的對(duì)未來(lái)的承諾。對(duì)于比較大的團(tuán)隊(duì)和比較大的項(xiàng)目來(lái)說(shuō),Hapi應(yīng)該成為首要選擇。它所推崇的配置優(yōu)于編碼,對(duì)團(tuán)隊(duì)和對(duì)團(tuán)隊(duì)一直追求的可復(fù)用性都大有裨益。現(xiàn)在趕緊行動(dòng)起來(lái)嘗試使用一個(gè)新的框架,可能你會(huì)喜歡或者討厭它,但沒(méi)到最后你總不會(huì)知道結(jié)果是怎么樣的,有一點(diǎn)無(wú)容置疑的是,它會(huì)讓你成為一個(gè)更好的開(kāi)發(fā)者。 英文原文:Node.js Framework Comparison: Express vs. Koa vs. Hapi |
|
來(lái)自: 念念爸 > 《NodeJs框架》