基於 Node.js 前後端分離的一點思考

sea_ljf發表於2018-01-27

hello~親愛的看官老爺們大家好~有一段時間沒寫文章了,最近忙於為一個對內的資料視覺化平臺進行完全的前後端分離。原來的專案是一個基於 Vue 的單頁應用,重構後接入 Node 作為中間層,達到完全的前後端分離。

由於專案相對簡單,成本並不是太高。下文將簡單介紹一下使用的技術棧與分離後的收益,重點是對基於 Node 做前後端分離的一點思考。

背景

大約是去年11月底入職新東家,接手一個僅 對內 的資料分析系統。新入職當然是希望做出點成績,在更改部分 UI 與優化部分功能之後,發現頁面效能還是比較低。排查後發現獲取資料的介面沒有快取,也不是基於 RESTful 的,瀏覽器快取完全不起作用。期間也經歷了後端修改介面,前端程式碼大面積修改的情況。

基於後端同學不熟悉前端機制,我也抱著方便日後搞事情的心態,在多次滾地板之後,部門 Leader 同意接入 Node 作為中間層。

技術選型

在確定接入 Node 後,首先要做的就是技術選型。Node 一般就是在 ExpressKoaEgg 中選。在中介軟體的使用上,個人偏好 Koa ,因而只好和 Express 說再見了 。Egg 是在 Koa 上作了強約束,規定程式碼編寫、目錄結構等。

選型時我與前端 Leader 討論了無數次,他認為 Egg 約束太多,擴充套件性較差,如若出現框架底層的 Bug 則難於處理,因而偏向於使用 Koa。這樣的顧慮十分合理,然而對於現在的專案而言,不太可能有功能會超出 Egg 所提供的,反而 Egg 所提供的功能能為專案搭建與維護減少不少的成本。至於約束,個人認為這反而是一件好事,一定程度上解決了多人開發時程式碼的組織問題。

考慮再三後,決定使用 Egg 作為 Node 的框架。

分離收益

由於專案不算十分複雜,接入的過程算是波瀾不驚。唯一的麻煩是工期比較緊,因而分兩步走:一期先接入 Node,所有頁端請求原樣轉發 Java,返回的結果原樣轉發頁端。二期對資料獲取的介面進行整合與優化以提升效能。完成後收益還是客觀的,貼兩張圖展示下成果。

原來某頁面的效能(所有請求都是 Post 的):

基於 Node.js 前後端分離的一點思考

接入 Node 相同頁面的效能(轉為方法為 Get):

基於 Node.js 前後端分離的一點思考

可以看到,不論是資料下載量還是響應時間等指標,耗時均有降低。當然,這是建立在接入 Node 後我對介面進行了整合與快取優化等措施後的對比。如果都是首次訪問,公司內網 WiFi 環境下與原來的效能會有稍差一點,整體載入時間略高於 Java 直出50ms不到。也用過 Chrome 模擬弱網環境,耗時與 Java 直出基本一致。

而且開發體驗上也比之前舒服得多,算是達到了接入 Node 前定下的目標:接入後在支援相同功能的情況下效能提高30%;在相同的開發時間內,完成相同的需求,但有更好的開發體驗及更好的頁端效能。

小結一下,前端的一切優化都是在模板與獲取模板所需資料上進行優化,使用 AngularReactVue 等框架構築的單頁應用,解決了模板的問題,可以不再讓後端去動我們的模板。但是獲取所需資料仍依賴於後端,不少單頁應用互動上已經足夠複雜,如果還需維護一套複雜的獲取與整合資料的邏輯,還是十分頭疼的。因而多接入一層 Node 處理資料的獲取與整合,盡最大努力去優化頁端的請求介面,讓頁端專注於互動,在條件成熟的情況下,是十分值得的。

思考

如若就為了推廣 Node,本文應該是把上面的步驟寫詳細,小結完就該結束了,這和很多大佬的實踐文章一致(當然我寫得不夠好~)。然而和兩位 Leader 的討論過程中,感謝他們對 Node 技術抱有懷疑,提出了不少有意思的問題,結合我自己的思考,整理成提問形式呈現給大家。

為何接入 Node 作為中間層,和公司現行的 PHP 有何區別?

沒有區別!事實說,Node 能做的 PHP 一樣能做。那麼問題就轉換為 Node 的意義是什麼,為何擯棄公司相對成熟的 PHP 方案而轉向 Node

我認為後端服務主要是穩定為主,業務調整不會特別頻繁。而對於前端而言,業務頻繁調整簡直司空見慣,如果前後端耦合在一起,頻繁讓後端發版不是可取之策。同時,前後端對資料結構的要求及對其控制的粒度也大不相同。寫得好 PHP 的同學不一定寫得好前端,寫得好前端的同學不一定寫得好 PHP。對於專業的領域,還是應該由專業的人去做,讓前端控制整個模板及模板依賴的資料,對提高專案質量有很大的幫助。說句玩笑話,後端就搞搞資料庫,吐吐 json 就好,前端就拿一下資料,切切頁面就好。

進一步而言,前端若要接入 SSR 之類的功能,Node 還真比 PHP 有優勢得多,也算是為日後搞事情做鋪墊吧。

接入 Node 後效能會有多大提高?

不一定有提高,甚至有下降。此問題是我一期完成之後,測試頁端效能時發現的。測試時,Node 除了將所有的需求原樣轉發外,還加了協商快取,然而響應時間卻更慢了。

接入前(為 Post 請求):

基於 Node.js 前後端分離的一點思考

接入後(為 Get 請求):

基於 Node.js 前後端分離的一點思考

正常來說,獲取 10k 左右的資料時,協商快取如若命中即返回 304,省略了下載的過程,理應更快的。通過打點,發現 Node 轉發請求耗時額外增加 10ms 左右,然而在全公司內網 WiFi 環境下,整體下載時間不到 160ms。

因而引入 Node 不一定會有效能的提高,反而會因為多引入一層,而導致效能耗損。在對內的專案中或效能尚可的專案中,提高效能不足以成為接入 Node 的關鍵理由。換句話說,接入 Node 之後,在優化頁端請求之前,並不可能為應用效能帶來飛躍。

這個問題也算是我對 Node 態度轉變的起點,開始從無腦支援接入 Node 到辯證地推敲,也引出之後的的問題。

接入 Node 有什麼弊端?

前端的能力越強,意味著責任越多。例如之前可能是 Java 做的安全防護,可能就會下沉到 Node 端,這對大多數前端同學而已都是比較陌生的領域。

投入的成本與產出也是值得商榷的事情,畢竟 Node 再貼近前端,也始終是屬於後端的領域。前後端思想不太一樣,用前端的思維寫後端,很可能寫出十分糟糕的程式碼,輕則影響效能,重則記憶體洩漏。接入 Node 層後它反而成為拖累,相信大家也不願看見。

畢竟 Node 對於不少公司而言是比較新的領域。儘管可能知道接入 Node 好處不少,但如何接入,接入後它能做什麼,大家可能比較模糊。如何花最少的代價,平滑地接入 Node 的同時,最大限度的複用現有架構,也是個不少的挑戰。

既然如此,沒有 Node 適用的場景嗎?

有。正如前文所說,Node 的意義是在於讓前端掌握模板與模板所依賴資料,不妨從這兩方面去進行考慮。如若重 SEO 的同時,頁面互動相對複雜,這時候接入 Node 作為中間層,我認為就是最佳實踐。

其次是後端架構不斷演變,開始轉向微服務化之後,前端感到介面碎片化開始帶來不少麻煩後,就應該考慮接入 Node 整合介面了。

總的來說,什麼時候接入 Node, 有點像什麼時候引入 ReduxVuex。當你感覺到麻煩後,只要你知道還有這個選項,自然而言地就會想到用它。

小結

綜上所述,在以下場景中,我認為接入 Node 是最佳實踐:

  • 重視 SEO 且互動複雜。
  • 後端微服務化,前端需要整合介面。
  • 前端主導的專案,需要用到最新技術,如 SSRPWA 等。

如若只是效能問題,引入 Node 不一定會有改善,需要根據實際情況進行分析。至於後端的介面設計太醜陋、返回的資料結構不符合前端使用等問題,在應用規模不大的情況下,其實都是可以和後端同學進行溝通的,以此接入 Node 不一定是最佳的實踐,需要好好思量。

但是,堅決反對只是因為現有架構比較熟悉而不願改變,始終抱著錯誤的方案不去解決的做法,這絕對是捨本逐末。我始終認為,只要是對的事情,儘管過程再艱難,亦應該朝著對的方向前進。

以上是個人的一點淺見,感謝各位看官大人看到這裡。知易行難,希望本文對你有所幫助~謝謝!

相關文章