express 最佳實踐 (一)
第二篇: express 最佳實踐(二):中間件
最近,一直在使用 nodejs 做項目,對 nodejs 開發可以說深有體會。
先說說 nodejs 在業務中的腳色,, 在 web同構 方面, nodejs 的優勢相對於其他語言來說,可以說非常巨大,基本上算是只有 nodejs 能做,其他語言根本不能做。在傳統 web 開發方面,nodejs(必竟時間太短了)的相對於其他語言來說的劣勢,已經不是太明顯了。
再來說說自己,算了算差不多做了 5 個項目,都是使用 express 做為項目的基礎框架,然后再上面進行業務開發工作,一個路由下來,平均 10 個左右的中間件,執行效率都是不錯的,開發效率也非常好,是時候總結一下 express 實踐經驗,同時結合配套自己的想法,來看看理想中 express 項目應該是怎樣的規划,以及我是怎么想的。
思想
做一個項目的規划,首先要為項目訂一個基調,就是項目架構是應該怎樣設計,怎樣考慮的,對業務開發是否方便,部署是否方便等要素。
我現在認為一個項目最重要的規划是:核心+插件式開發。一個項目一定要支持這兩點,如果不支持這個項目就很難做下去,為什么我這樣說。因為現在的任何一個項目都不可能是一個人開發,一定是多人分工開發,如果你的項目支持 核心+插件式開發,你就可以把核心的基礎功能如:網絡,日志,基礎布局等功能,找個高級工程師來完成;業務開發,就可以分給一些初級工程師,並行完成,同時在做項目的時候對代碼碼進行審查,及時調整壞代碼。這樣項目,能保證進度,也能保證項目質量,不會大爛,同時人力也得到了充分利用。
這種思想落實到架構上,就是從項目的文件組織結構上考慮怎樣達到這樣的目標。
我是這樣規划文件目錄的:
按業務特性而不按分層進行規划
分層最典型的代表就是ruby on rails,app 目錄下,就是 controllers, models等目錄,當然我不是說,這種規划不好,只是到項目大到一定程度,你想找某個 controller 下的一個方法,就會很麻煩,不知道沒有這種體驗,在幾十個文件中找某個方法是怎樣的感覺,搜索也是全文搜索,不能限定到某個目錄下面。因此在這個項目規划中,以業務特征為插件名,在 express 中,也就是 subExpress,如果,我有一個購物車的業務,那於購物車相關的所有的項目都規在 passport 這個子應用下了,這樣相關的業務在一起,方便查找,同時也方便理解和修改。當然這種規划方式也有不方便的地方,如果想跨 subApplication 調用方法,就沒有那么方便。
邊界顯式說明
這個跟傳統的 controller, service , model 沒有什么區別。還是剛才的 passport 應用,按分層進行划分,包括 controllers, services, models, views, index.js, router.js。需要說明一下,在項目中我們一再強調, controllers 中負責與 http 的連接工作,只做簡單參數的驗證,傳參和調起 services ,禁止把 rep, res 對像做為參數傳遞到 services 層;services 層純業務,沒有與 http 相關的任何東西,需要數據請調用 models 中的方法;models 只於數據打交到,其它都不管。這樣做的好處是什么呢? 想想看,如果相把一個頁面的數據拿出來做接口,只需要簡單幾行就搞定了,還有如果要把框架改成 koa ,你的業務都不用重寫,還有你想增加 websocket 的支持,直接在 controllers 進行調整就行了。 models的作用更明顯,原來的項目是一個普通是 web 項目,models 是連接數據庫的,現在技術升級要前后端分離,不用數據庫了,改成調用后端的接口了,你就只用把 models 用接口實現一遍,其他不用變了。 controllers 和 models 就是你業務的邊界,service 則是你業務的核心,邊界實現的改變不應該影響你業務。
落實
思想利用 express 的中間件思想,達到我的架構意圖,如下圖所示:

圖中,藍色的部分代表業務中間件,橙黃色代表 核心中間件。在一個網站項目中核心中間件,應該包括 limiter 限流操作,這個中間件主要是防止爬蟲;htaccess 改寫 url,這個中間件主要用,改寫網站url, 為什么要改呢?因為一但網站線上運行時,路由的規則不應發生變化,但是有時候 seo 的時候,你需要兼容新老 url 的時候,這個中間件就會非常有用,網站的業務都不用變,只用在新url 到達時,變成老的再進行處理就行了;dispatch 不是一個中間件,它的思想是用來整合各個業務線的 subApplication 和主 application 的關系的;auth 鑒權,有些頁面和接口需要有用戶登錄,如果沒有用戶登錄,就需要跳轉到登錄頁面,登錄完成后跳回來;clientError 和 serverError 是對錯誤進行統一的處理,統一顯示 404 , 如果是接口的話也會統一 404 的返回碼。
業務端在開發時只需要在 dispatch 的地方加入自已的模塊,然后就可以開始寫自己的業務,不用但心自己的文件被別人改動。
下面是項目的文件夾規划:

簡單說明下:
apps 目錄下就寫各自的業務邏輯,用 dispatch 把 主app 與 業務 連接起來,實現起來也挺簡單的:
module.exports = (app) => {
app.use('/passport', require('./apps/passport'));
}
還有 shared 的存在,是為了解決前后端模板公用的問題。
與業務沒有關系的代碼可以,移到到 modules 中使用。
如果個業務的之間需要共享部分代碼,就放到 utils 中,這個文件夾就是用來干這種事的。
總結
這個項目中規划就是,怎樣使用 express 最好,另外再加上自己的一些思考,現在項目的結構出來了,后面會再討論一些有關中間件的處理方法。
該項目的 github
