為什么需要前后分離
后端為主的 MVC 時代
為了降低開發的復雜度,以后端為出發點,比如:Struts、SpringMVC 等框架的使用,就是后端的 MVC 時代;可以參考 【什么是 MVC 模式】
以 SpringMVC
流程為例:
- 發起請求到前端控制器(
DispatcherServlet
) - 前端控制器請求
HandlerMapping
查找Handler
,可以根據xml
配置、注解進行查找 - 處理器映射器
HandlerMapping
向前端控制器返回Handler
- 前端控制器調用處理器適配器去執行
Handler
- 處理器適配器去執行
Handler
-
Handler
執行完成給適配器返回ModelAndView
- 處理器適配器向前端控制器返回
ModelAndView
,ModelAndView
是SpringMVC
框架的一個底層對象,包括Model
和View
- 前端控制器請求視圖解析器去進行視圖解析,根據邏輯視圖名解析成真正的視圖(
JSP
) - 視圖解析器向前端控制器返回
View
- 前端控制器進行視圖渲染,視圖渲染將模型數據(在
ModelAndView
對象中)填充到request
域 - 前端控制器向用戶響應結果
優點
MVC 是一個非常好的協作模式,能夠有效降低代碼的耦合度,從架構上能夠讓開發者明白代碼應該寫在哪里。為了讓 View 更純粹,還可以使用 Thymeleaf、Freemarker 等模板引擎,使模板里無法寫入 Java 代碼,讓前后端分工更加清晰。
缺點
- 前端開發重度依賴開發環境,開發效率低,這種架構下,前后端協作有兩種模式:
- 第一種是前端寫 DEMO,寫好后,讓后端去套模板。好處是 DEMO 可以本地開發,很高效。不足是還需要后端套模板,有可能套錯,套完后還需要前端確定,來回溝通調整的成本比較大;
- 另一種協作模式是前端負責瀏覽器端的所有開發和服務器端的 View 層模板開發。好處是 UI 相關的代碼都是前端去寫就好,后端不用太關注,不足就是前端開發重度綁定后端環境,環境成為影響前端開發效率的重要因素。
- 前后端職責糾纏不清:模板引擎功能強大,依舊可以通過拿到的上下文變量來實現各種業務邏輯。這樣,只要前端弱勢一點,往往就會被后端要求在模板層寫出不少業務代碼。還有一個很大的灰色地帶是
Controller
,頁面路由等功能本應該是前端最關注的,但卻是由后端來實現。Controller
本身與Model
往往也會糾纏不清,看了讓人咬牙的業務代碼經常會出現在Controller
層。這些問題不能全歸結于程序員的素養,否則 JSP 就夠了。 - 對前端發揮的局限性:性能優化如果只在前端做空間非常有限,于是我們經常需要后端合作,但由于后端框架限制,我們很難使用 【Comet】、【BigPipe】 等技術方案來優化性能。
注:在這期間(2005 年以前),包括早期的 JSP
、PHP
可以稱之為 Web 1.0
時代。在這里想說一句,如果你是一名 Java 初學者,請你不要再把一些陳舊的技術當回事了,比如 JSP
,因為時代在變、技術在變、什么都在變(引用扎克伯格的一句話:唯一不變的是變化本身
);當我們 千鋒教育
機構去給大學做實訓時,有些同學會認為我們沒有講什么 干貨
,其實不然,只能說是你認知里的干貨對于市場來說早就過時了而已。
什么是前后分離
基于 AJAX 帶來的 SPA 時代
時間回到 2005 年 AJAX
(Asynchronous JavaScript And XML,異步 JavaScript 和 XML,老技術新用法) 被正式提出并開始使用 CDN
作為靜態資源存儲,于是出現了 JavaScript 王者歸來(在這之前 JS 都是用來在網頁上貼狗皮膏藥廣告的)的 SPA(Single Page Application)單頁面應用時代。
優點
這種模式下,前后端的分工非常清晰,前后端的關鍵協作點是 AJAX
接口。看起來是如此美妙,但回過頭來看看的話,這與 JSP 時代區別不大。復雜度從服務端的 JSP 里移到了瀏覽器的 JavaScript,瀏覽器端變得很復雜。類似 Spring MVC,這個時代開始出現瀏覽器端的分層架構:
缺點
-
前后端接口的約定: 如果后端的接口一塌糊涂,如果后端的業務模型不夠穩定,那么前端開發會很痛苦;不少團隊也有類似嘗試,通過接口規則、接口平臺等方式來做。有了和后端一起沉淀的
接口規則
,還可以用來模擬數據,使得前后端可以在約定接口后實現高效并行開發。 - 前端開發的復雜度控制: SPA 應用大多以功能交互型為主,JavaScript 代碼過十萬行很正常。大量 JS 代碼的組織,與 View 層的綁定等,都不是容易的事情。
前端為主的 MV* 時代
此處的 MV* 模式如下:
- MVC(同步通信為主):Model、View、Controller
- MVP(異步通信為主):Model、View、Presenter
- MVVM(異步通信為主):Model、View、ViewModel
為了降低前端開發復雜度,涌現了大量的前端框架,比如:AngularJS
、React
、Vue.js
、EmberJS
等,這些框架總的原則是先按類型分層,比如 Templates、Controllers、Models,然后再在層內做切分,如下圖:
優點
- 前后端職責很清晰: 前端工作在瀏覽器端,后端工作在服務端。清晰的分工,可以讓開發并行,測試數據的模擬不難,前端可以本地開發。后端則可以專注于業務邏輯的處理,輸出 RESTful等接口。
- 前端開發的復雜度可控: 前端代碼很重,但合理的分層,讓前端代碼能各司其職。這一塊蠻有意思的,簡單如模板特性的選擇,就有很多很多講究。并非越強大越好,限制什么,留下哪些自由,代碼應該如何組織,所有這一切設計,得花一本書的厚度去說明。
- 部署相對獨立: 可以快速改進產品體驗
缺點
- 代碼不能復用。比如后端依舊需要對數據做各種校驗,校驗邏輯無法復用瀏覽器端的代碼。如果可以復用,那么后端的數據校驗可以相對簡單化。
- 全異步,對 SEO 不利。往往還需要服務端做同步渲染的降級方案。
- 性能并非最佳,特別是移動互聯網環境下。
- SPA 不能滿足所有需求,依舊存在大量多頁面應用。URL Design 需要后端配合,前端無法完全掌控。
NodeJS 帶來的全棧時代
前端為主的 MV* 模式解決了很多很多問題,但如上所述,依舊存在不少不足之處。隨著 NodeJS 的興起,JavaScript 開始有能力運行在服務端。這意味著可以有一種新的研發模式:
在這種研發模式下,前后端的職責很清晰。對前端來說,兩個 UI 層各司其職:
- Front-end UI layer 處理瀏覽器層的展現邏輯。通過 CSS 渲染樣式,通過 JavaScript 添加交互功能,HTML 的生成也可以放在這層,具體看應用場景。
- Back-end UI layer 處理路由、模板、數據獲取、Cookie 等。通過路由,前端終于可以自主把控 URL Design,這樣無論是單頁面應用還是多頁面應用,前端都可以自由調控。后端也終于可以擺脫對展現的強關注,轉而可以專心于業務邏輯層的開發。
通過 Node,Web Server 層也是 JavaScript 代碼,這意味著部分代碼可前后復用,需要 SEO 的場景可以在服務端同步渲染,由于異步請求太多導致的性能問題也可以通過服務端來緩解。前一種模式的不足,通過這種模式幾乎都能完美解決掉。
與 JSP 模式相比,全棧模式看起來是一種回歸,也的確是一種向原始開發模式的回歸,不過是一種螺旋上升式的回歸。
基于 NodeJS 的全棧模式,依舊面臨很多挑戰:
- 需要前端對服務端編程有更進一步的認識。比如 TCP/IP 等網絡知識的掌握。
- NodeJS 層與 Java 層的高效通信。NodeJS 模式下,都在服務器端,RESTful HTTP 通信未必高效,通過 SOAP 等方式通信更高效。一切需要在驗證中前行。
- 對部署、運維層面的熟練了解,需要更多知識點和實操經驗。
- 大量歷史遺留問題如何過渡。這可能是最大最大的阻力。
注:看到這里,相信很多同學就可以理解,為什么我總在課堂上說:“前端想學后臺很難,而我們后端程序員學任何東西都很簡單”;就是因為我們后端程序員具備相對完善的知識體系。
總結
綜上所述,模式也好,技術也罷,沒有好壞優劣之分,只有適合不適合;前后分離的開發思想主要是基于 SoC
(關注度分離原則),上面種種模式,都是讓前后端的職責更清晰,分工更合理高效。