相信前後端分離這個詞,早已流傳甚廣,大家一些自己的理解,但可能有些人的觀點有稍許偏差:我們要搞 SPA,全AJAX,那才是前後端分離了。
什麼是前後端分離
我們來聊聊什麼是前後端分離。
先來看一張WEB系統前後端架構模型圖。
從圖中可以清晰的看到,前後端的界限是按照瀏覽器和伺服器的劃分。那麼我們經常會發現一些問題:
- 模板層歸屬前端還是後端?
- 模板強依賴於後端渲染,前端開發需要等待後端開發嗎?
通常情況,模板層歸屬於前端,因為讓後端人員來接觸他們不擅長的樣式和 js 互動是很蛋疼的事情。
那麼,作為前端開發的我們在實際的開發場景中又會遇到以下問題:
- 環境:進行本地開發,需要起後端環境,如 Tomcat、PHP,影響開發效率
- 流程:前端開發先開發 html,再將 html 改寫成指定的模板語法(俗稱套模板),影響開發效率
- 介面:
- 介面定義一般使用 word 文件,前端開發時不好理解介面欄位,影響開發效率
- 介面變更需要重新編寫文件,並重新傳送,影響開發效率
- 文件散落,影響介面維護
- 聯調:
- 聯調過程變得很複雜,尤其是沒有做熱部署的Java工程,改檢視還需要重啟Tomcat,影響前端聯調效率
- 效益:
- 前端開發更關注使用者體驗,而後端只希望關注資料可靠,為實現如響應式、ssr之類的一些互動,前端需要掌控一定的請求響應能力
- 如果前後端對接的方式轉變成為純粹的 JSON 交換,對於提升開發效率、更清晰的職責與介面複用都是有好處的
出現影響開發效率的事情,就說明現有的模式存在問題,顯然問題的解題思路需要我們重新思考“前後端”的定義。此時,前後端分離的概念便應運而生,目的是將前後端開發人員的合作方式調節到大家都儘可能舒適的姿勢。
有哪些實現方案
SPA
全稱 Single Page Application,使用前端路由的方式代替後端的 controller,並使用前端模板代替後端的模板引擎渲染,使用 restful api 實現與後端的資料互動。
在這個方案中,前後端的互動被轉換成了純粹的 http 方式的 JSON 串互動。
SPA 的優勢:
- 環境:前端開發者不需要本地起後端環境
- 流程:獨立的前端開發方式,由於後端返回純 JSON ,前端想要模擬請求響應的話,只需啟動一個純靜態的伺服器,響應 JSON 格式的 html 即可
- 聯調:清晰的對接方式,JSON 對於前後端來說都是比較純粹的
- 效益:對於使用者來說,使用者體驗的提升
SPA 的劣勢
- SEO 弱
- 首屏載入慢,等所有 js 載入完才能出首屏
- 前端需要處理一些本不需要在這一層處理的事情,如許可權控制交給前端控制
綜上,SPA 是一個可以解決前後端分離的有效方案,對於無 SEO 要求的專案大可以嘗試。
開發階段的分離 -- Mock && Proxy
顧名思義,開發階段的前後端分離,需要依賴工具實現,通常把這個工具叫做 Mock Server(如筆者所開發的一款 Mock Server -- Foxman)。
Mock Server 提供功能
基礎功能
- 攔截同步請求,取 JSON 格式的 Mock 資料,結合本地 Template,通過模板渲染引擎渲染,得出響應的頁面
- 攔截非同步請求,取 JSON 格式的 Mock 資料響應
這裡我們需要抽象以上操作為兩個函式,利於理解:
- SyncView = TemplateEngine(Template, MockData)
- AsyncView = MockDataTransform(MockData)
優化功能
- Living Reload -- 監聽本地檔案,發生修改則通知(一般使用 websocket)瀏覽器更新資源
- 修改響應頭 -- Mock 階段,可以做到 js 修改響應情況
- 代理 -- 前面提到了兩個函式,代理的指責是將原本取自本地的 MockData,改成了從服務端以 http 的方式取得的資料
開發流程
我們將一個專案開發劃分為三個階段:介面定義,開發,聯調。正好可以和我們 “Mock”、 “Proxy” 兩個工具契合。
讓我們通過實際的場景來表述這種前後端的合作方式。
介面定義
我們接到一個需求,實現某個功能。在我們理清楚具體的功能之後,應該與後端定義介面及返回,包括:
- 有哪些頁面,頁面的請求路徑,模板位置,以及後端返回給我們的 Model 內容
- 有哪些 Ajax 介面,Ajax介面 的請求路徑,以及後端返回的 JSON 內容
在制定完介面後,我們需要按照 Mock Server 的要求,建立 Mock 檔案,並往裡面填入與後端約定好的 JSON 資料,並與後端確認。
顯然我們的開發中,介面定義變成了一件很具體的事情,而開發階段可以使用這份 Mock 資料,並做到 Mock 資料即介面文件
開發階段
在我們完成介面定義後,我們期望的是無打擾、自治的一個開發體驗。
正如上圖所示,開發階段前端開發可以完全與後端開發人員隔絕,也不需要本地啟動後端環境,我們要做的,只是按照先前指定的介面及本地的 Mock 檔案進行需求的開發。
而在開發過程中,遵循 html -> css -> js 的開發順序,Foxman 擁有一個很人性化的 live reload(更改css 之會 reload css),總之介面定義合理的話,這一步會很順暢。
聯調階段
在我們開發完頁面後,我們期望的是與後端進行聯合除錯,已驗證功能開發是否存在缺陷,即聯調階段。
在這步驟中,我們只需要更換 SyncView = TemplateEngine(Template, MockData)
的 MockData,將原本響應自 Mock 檔案的請求,轉發到真實的目標伺服器(在聯調階段會是 開發主機 或者 測試機)。
此處代理和轉發,筆者已抽象成了的另外一個庫 koa-api-forward,歡迎交流和使用。
Mock && Proxy 優勢
- 環境:
- 前端開發者不需要本地起後端環境
- 流程:
- 獨立的前端開發方式,Mock 與 Proxy 結合,流程清晰
- 前端可以在本地除錯 view 層,大幅度提升前端的聯調效率
- 聯調:
- 清晰的對接方式,JSON 實現前後端來說都是比較純粹的
- 效益:
- 方便開發的同時,保持線上系統的無侵入
Mock && Proxy 劣勢
- 未真正掌握線上的介面響應,實現一些前端互動需求(響應式)時仍依賴後端,或無法進行(如 ssr)
Node.js 中間層
這個模式自然時結合了前面的 Proxy。大家都知道 Node.js Server 裡面強調一個 中介軟體的 概念,對應到設計模式的職責鏈模式。即只處理自己能處理的情況,否則,繼續往後傳遞,直到被處理。
這個方案中,Proxy 作為了中介軟體體系中的最後一層,用以轉發請求,而在這之前依次是中介軟體的錯誤處理、靜態資源的響應、路由攔截(routers) 等等。
Node.js 擁有一定的介面控制能力,如處理 PC/Mobile 的響應式渲染,或是 Server-Side-Render 等等。
Node.js 中間層優勢
- 環境:
- 前端開發者不需要本地起後端環境
- 聯調:
- 清晰的對接方式,JSON 實現前後端來說都是比較純粹的
- 效益:
- 可漸進式,前期可以將請求全部轉發後端伺服器,而後可以逐步將 Node.js 層作為使用者的直接資料交換層
- 職責分明,後端服務化,Node.js 層處理介面使用者相關的頁面響應 及 資料交換
- 可組合性,後端服務化,Node.js 負責組合拼裝,實現介面可複用率
Node.js 中間層劣勢
- 開發階段仍需要 Mock 支援,如果將 Mock 方式整合進 Node.js 中間層,則造成 Node.js 中間層職責不純粹
- 對現有系統的漸進式改造是個較為漫長的過程
總結
還是那句話,所有的前後端分離方案,都是為了前後端開發人員的合作方式調節到大家都儘可能舒適的姿勢。
那麼一個不錯的實踐是,我們可以將 (Mock && Proxy) 與 Node.js 中間層 兩個方案結合:
- Mock && Proxy 只依靠抽象出來的工具,在前端開發階段,繼續使用,避免造成 Node.js 中間層職責不純粹
- Node.js 中間層的存在可以解決(Mock && Proxy)方案的劣勢
未完待續。。。
參考資料
by 君羽