Node.js的願望是成爲一個能構建高速,可伸縮的網絡應用的平臺,它自己具備基於事件,異步,非阻塞,回調等特性,這在前幾篇專欄中有過描述。正是基於這樣的一些特性,Node.js平臺上的Web框架也具備不一樣於其餘平臺的一些特性,其中Connect是衆多Web框架中的佼佼者。
Connect在它的官方介紹中,它是Node的一箇中間件框架。超過18個捆綁的中間件和一些精選第三方中間件。儘管Connect可能不是性能最好的Node.jsWeb框架,但它卻幾乎是最爲流行的Web框架。爲什麼Connect能在衆多框架中勝出,其緣由不外乎有以下幾個: 前端
Connect自身十分簡單,其做用是基於Web服務器作中間件管理。至於如何如何處理網絡請求,這些任務經過路由分派給管理的中間件們進行處理。它的處理模型僅僅只是一箇中間隊列,進行流式處理而已,流式處理可能性能不是最優,可是倒是最易於被理解和接受。基於中間件能夠自由組合和插拔的狀況,優化它十分容易。
Connect模塊目前在NPM倉庫的MDO(被依賴最多的模塊)排行第八位。但這並無真實反映出它的價值,由於排行第五位的Express框架其實是依賴Connect建立而成的。關於Express的介紹,將會在後續的專欄中一一爲你講解。 node
讓咱們回顧一下Node.js最簡單的Web服務器是如何編寫的: git
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(1337, '127.0.0.1');
咱們從最樸素的Web服務器處理流程開始,能夠看到HTTP模塊基於事件處理網絡訪問無外乎兩個主要的因素,請求和響應。同理的是Connect的中間件也是扮演這樣一個角色,處理請求,而後響應客戶端或是讓下一個中間件繼續處理。以下是一箇中間件最樸素的原型: github
function (req, res, next) { // 中間件 }
在中間件的上下文中,有着三個變量。分別表明請求對象、響應對象、下一個中間件。若是當前中間件調用了res.end()結束了響應,執行下一個中間件就顯得沒有必要。 npm
爲了演示中間件的流式處理,咱們能夠看看中間件的使用形式: json
var app = connect(); // Middleware app.use(connect.staticCache()); app.use(connect.static(__dirname + '/public')); app.use(connect.cookieParser()); app.use(connect.session()); app.use(connect.query()); app.use(connect.bodyParser()); app.use(connect.csrf()); app.use(function (req, res, next) { // 中間件 }); app.listen(3001);
Conncet提供use方法用於註冊中間件到一個Connect對象的隊列中,咱們稱該隊列叫作中間件隊列。 後端
Conncet的部分核心代碼以下,它經過use方法來維護一箇中間件隊列。而後在請求來臨的時候,依次調用隊列中的中間件,直到某個中間件再也不調用下一個中間件爲止。 服務器
app.stack = []; app.use = function(route, fn){ // … // add the middleware debug('use %s %s', route || '/', fn.name || 'anonymous'); this.stack.push({ route: route, handle: fn }); return this; };
值得注意的是,必需要有一箇中間件調用res.end()方法來告知客戶端請求已被處理完成,不然客戶端將一直處於等待狀態。
流式處理也是Node.js中用於流程控制的經典模式,Connect模塊是典型的應用了它。流式處理的好處在於,每個中間層的職責都是單一的,開發者經過這個模式能夠將複雜的業務邏輯進行分解。 cookie
從前文能夠看到其實app.use()方法接受兩個參數,route和fn,既路由信息和中間件函數,一個完整的中間件,其實包含路由信息和中間件函數。路由信息的做用是過濾不匹配的URL。請求在碰見路由信息不匹配時,直接傳遞給下一個中間件處理。
一般在調用app.use()註冊中間件時,只須要傳遞一箇中間件函數便可。實際上這個過程當中,Connect會將/做爲該中間件的默認路由,它表示全部的請求都會被該中間件處理。
中間件的優點相似於Java中的過濾器,可以全局性地處理一些事務,使得業務邏輯保持簡單。
任何事物均有兩面性,當你調用app.use()添加中間件的時候,須要考慮的是中間件隊列是否太長,由於每一層中間件的調用都是會下降性能的。爲了提升性能,在添加中間件的時候,如非全局需求的,儘可能附帶上精確的路由信息。
以multipart中間件爲例,它用於處理表單提交的文件信息,相對而言較爲耗費資源。它存在潛在的問題,那就是有可能被人在客戶端惡意提交文件,形成服務器資源的浪費。若是不採用路由信息加以限制,那麼任何URL均可以被攻擊。 網絡
app.use("/upload", connect.multipart({ uploadDir: path }));
加上精確的路由信息後,能夠將問題減少。
藉助Connect能夠自由定製中間件的優點,能夠自行提高性能或是設計出適合本身須要的項目。Connect自身提供了路由功能,在此基礎上,能夠輕鬆搭建MVC模式的框架,以達到開發效率和執行效率的平衡。如下是筆者項目中採用的目錄結構,清晰地劃分目錄結構能夠幫助劃分代碼的職責,此處僅供參考。
├── Makefile // 構建文件,一般用於啓動單元測試運行等操做 ├── app.js // 應用文件 ├── automation // 自動化測試目錄 ├── bin // 存放啓動應用相關腳本的目錄 ├── conf // 配置文件目錄 ├── controllers // 控制層目錄 ├── helpers // 幫助類庫 ├── middlewares // 自定義中間件目錄 ├── models // 數據層目錄 ├── node_modules // 第三方模塊目錄 ├── package.json // 項目包描述文件 ├── public // 靜態文件目錄 │ ├── images // 圖片目錄 │ ├── libs // 第三方前端JavaScript庫目錄 │ ├── scripts // 前端JavaScript腳本目錄 │ └── styles // 樣式表目錄 ├── test // 單元測試目錄 └── views // 視圖層目錄
田永強,新浪微博@樸靈,前端工程師,曾就任於SAP,現就任於淘寶,花名樸靈,致力於NodeJS和Mobile Web App方面的研發工做。雙修先後端JavaScript,寄望將NodeJS引薦給更多的工程師。興趣:讀萬卷書,行萬里路。我的Github地址:http://github.com/JacksonTian。