自然是有很大意義的。下面我可能說的比較多……方便題主能夠更全面的了解為什么說是有有意義的。另外,本文是以Java的角度談前后端分離。放心,大家一定會有種是我了,沒錯,的感覺。
一、先來明晰下概念
前后端分離是通過Ngnix+Tomcat的方式(也可以中間加一個Node.js)有效的進行解耦,並且前后端分離會為以后的大型分布式架構、彈性計算架構、微服務架構、多端化服務(多種客戶端,例如:瀏覽器,車載終端,安卓,iOS等等)打下堅實的基礎。這個步驟是系統架構從猿進化成人的必經之路。
它的核心思想是前端HTML頁面通過Ajax調用后端的Restful API接口並使用json數據進行交互。這點題主也有提到。
二、其次,讓我們了解下,沒有前后端分離的時代(各種耦合)
過去,Java Web項目大多數都是Java程序員又當爹又當媽,又搞前端,又搞后端。
感覺就是,懷疑猿生……
那時的JavaWeb項目都是使用了若干后台框架,Spring MVC/Struts + Spring + Spring JDBC/Hibernate/Mybatis 等等。
大多數項目在Java后端都是分了三層,控制層,業務層,持久層。控制層負責接收參數,調用相關業務層,封裝數據,以及路由&渲染到JSP頁面。然后JSP頁面上使用各種標簽或者手寫Java表達式將后台的數據展現出來,玩的是MVC那套思路。
我們先看這種情況:需求定完了,代碼寫完了,測試測完了,然后呢?要發布了吧?你需要用maven或者eclipse等工具把你的代碼打成一個war包,然后把這個war包發布到你的生產環境下的web容器里,對吧?
發布完了之后,你要啟動你的Web容器,開始提供服務,這時候你通過配置域名,DNS等等相關,你的網站就可以訪問了(假設你是個網站)。那我們來看,你的前后端代碼是不是全都在那個war包里?包括你的js,css,圖片,各種第三方的庫,對吧?
好,下面在瀏覽器中輸入你的網站域名(http://www.xxx.com),之后發生了什么?
瀏覽器在通過域名通過DNS服務器找到服務器外網ip,將http請求發送到服務器,在tcp3次握手之后(http下面是tcp/ip),通過tcp協議開始傳輸數據,服務器得到請求后,開始提供服務,接收參數,之后返回應答給瀏覽器,瀏覽器再通過content-type來解析返回的內容,呈現給用戶。
那么我們來看,我們先假設你的首頁中有100張圖片,此時,用戶的看似一次http請求,其實並不是一次,用戶在第一次訪問的時候,瀏覽器中不會有緩存,100張圖片,瀏覽器要連着請求100次http請求,服務器接收這些請求,都需要耗費內存去創建socket來玩tcp傳輸。
重點來了,這樣的話,服務器的壓力會非常大,因為頁面中的所有請求都是只請求到這台服務器上,如果1個人還好,如果10000個人並發訪問呢,那服務器能扛住多少個tcp連接?帶寬有多大?服務器的內存有多大?硬盤是高性能的嗎?能抗住多少IO?web服務器分的內存有多大?會不會宕機?
這就是為什么,越是大中型的web應用,他們越是要解耦。理論上可以把數據庫+應用服務+消息隊列+緩存+用戶上傳的文件+日志+等等都扔在一台服務器上,這也不用玩什么服務治理,也不用做什么性能監控,什么報警機制等等,就亂成一鍋粥好了。但是這樣就好像是把雞蛋都放在一個籃子里,隱患非常大。如果因為一個子應用的內存不穩定導致整個服務器內存溢出而hung住,那整個網站就掛掉了。
如果出意外掛掉,而恰好這時你們的業務又處於井噴式發展高峰期,業務成功被技術卡住,很可能會流失大量用戶,后果不堪設想。
此外,應用全部都耦合在一起,相當於一個巨石,當服務端負載能力不足時,一般會使用負載均衡的方式,將服務器做成集群,這樣其實你是在水平擴展一塊塊巨石,性能加速度會越來越低,要知道,本身負載就低的功能or模塊是沒有必要水平擴展的,在本文中的例子就是性能瓶頸不在前端,那干嘛要水平擴展前端呢?還有發版部署上線的時候,明明只改了后端的代碼,為什么要前端也跟着發布呢?
正常的互聯網架構,是都要拆開的,web服務器集群,應用服務器集群+文件服務器集群+數據庫服務器集群+消息隊列集群+緩存集群等等。
三、不分離,JSP的痛點,前端工程師的痛點,扎心……
以前的Java Web項目大多數使用JSP作為頁面層展示數據給用戶,因為流量不高,因此也沒有那么苛刻的性能要求。但現在是大數據時代,對於互聯網項目的性能要求是越來越高,因此原始的前后端耦合在一起的架構模式已經逐漸不能滿足我們,因此我們需要需找一種解耦的方式,來大幅度提升我們的負載能力。
動態資源和靜態資源全部耦合在一起,服務器壓力大,因為服務器會收到各種http請求,例如css的http請求,js的,圖片的等等。一旦服務器出現狀況,前后台一起玩完,用戶體驗極差。 UI出好設計圖后,前端工程師只負責將設計圖切成HTML,需要由Java工程師來將HTML套成JSP頁面,出錯率較高(因為頁面中經常會出現大量的js代碼),修改問題時需要雙方協同開發,效率低下。
JSP必須要在支持Java的Web服務器里運行(例如Tomcat,Jetty,resin等),無法使用Ngnix等(Ngnix據說單實例http並發高達5w,這個優勢要用上),性能提不上來。 第一次請求JSP,必須要在Web服務器中編譯成Servlet,第一次運行會較慢。
每次請求JSP都是訪問servlet再用輸出流輸出的html頁面,效率沒有直接使用HTML高(是每次喲,親~)。 jsp內有較多標簽和表達式,前端工程師在修改頁面時會捉襟見肘,遇到很多痛點。 如果jsp中的內容很多,頁面響應會很慢,因為是同步加載。 需要前端工程師使用Java的IDE(例如eclipse),以及需要配置各種后端的開發環境,你們有考慮過前端工程師的感受嗎?
四、So!前后端分離后的意義?它可解決以上的(及未列的)大部分“矛盾”
前后端分離可以實現真正的前后端解耦,前端服務器使用Ngnix。
前端/Web服務器放的是css,js,圖片等等一系列靜態資源(甚至你還可以css,js,圖片等資源放到特定的文件服務器,例如阿里雲的OSS,並使用CDN加速),前端服務器負責控制頁面引用&跳轉&路由,前端頁面異步調用后端的接口,后端/應用服務器使用Tomcat(把Tomcat想象成一個數據提供者),加快整體響應速度。(這里需要使用一些前端工程化的框架比如Node.js,React,router,redux,webpack) 發現bug,可以快速定位是誰的問題,不會出現互相踢皮球的現象。頁面邏輯,跳轉錯誤,瀏覽器兼容性問題,腳本錯誤,頁面樣式等問題,全部由前端工程師來負責。接口數據出錯,數據沒有提交成功,應答超時等問題,全部由后端工程師來解決。
雙方互不干擾,前端與后端是相親相愛的一家人。
另外,在大並發情況下,我可以同時水平擴展前后端服務器,比如某寶的一個首頁就需要2000+台前端服務器做集群來抗住日均多少億+的日均pv。(去參加阿里的技術峰會,聽他們說他們的web容器都是自己寫的,就算他單實例抗10萬http並發,2000台是2億http並發,並且他們還可以根據預知洪峰來無限拓展,很恐怖,就一個首頁。。。) 減少后端服務器的並發/負載壓力。
除了接口以外的其他所有http請求全部轉移到前端Ngnix上,接口的請求調用Tomcat,參考Ngnix反向代理Tomcat。且除了第一次頁面請求外,瀏覽器會大量調用本地緩存。 即使后端服務暫時超時或者宕機了,前端頁面也會正常訪問,只不過數據刷不出來而已。
也許你也需要有微信相關的輕應用,那樣你的接口完全可以共用,如果也有app相關的服務,那么只要通過一些代碼重構,也可以大量復用接口,提升效率。(多端應用) 頁面顯示的東西再多也不怕,因為是異步加載。 nginx支持頁面熱部署,不用重啟服務器,前端升級更無縫。 增加代碼的維護性&易讀性(前后端耦在一起的代碼讀起來相當費勁)。
提升開發效率。因為可以前后端並行開發,而不是像以前的強依賴。 在Ngnix中部署證書,外網使用https訪問,並且只開放443和80端口,其他端口一律關閉(防止×××端口掃描),內網使用http,性能和安全都有保障。 前端大量的組件代碼得以復用,組件化,提升開發效率,抽出來。
五、再說說分離前后的對比吧,比如,開發模式、請求方式
開發模式
以前老的方式是:
產品經歷/領導/客戶提出需求
UI做出設計圖
前端工程師做HTML頁面
后端工程師將HTML頁面套成JSP頁面(前后端強依賴,后端必須要等前端的HTML做好才能套JSP。如果HTML發生變更,就更痛了,開發效率低)
集成出現問題
前端返工
后端返工
二次集成
集成成功
交付
新的方式是:
產品經歷/領導/客戶提出需求
UI做出設計圖
前后端約定接口&數據&參數
前后端並行開發(無強依賴,可前后端並行開發,如果需求變更,只要接口&參數不變,就不用兩邊都修改代碼,開發效率高)
前后端集成
前端頁面調整
集成成功
交付
請求方式
以前老的方式是:
客戶端請求
服務端的Servlet或Controller接收請求(后端控制路由與渲染頁面,整個項目開發的權重大部分在后端)
調用Service,Dao代碼完成業務邏輯
返回JSP
JSP展現一些動態的代碼
新的方式是:
瀏覽器發送請求
直接到達HTML頁面(前端控制路由與渲染頁面,整個項目開發的權重前移)
HTML頁面負責調用服務端接口產生數據(通過Ajax等等,后台返回json格式數據,JSON數據格式因為簡潔高效而取代XML)
填充HTML,展現動態效果,在頁面上進行解析並操作DOM。
總結一下新的方式的請求步驟:
大量並發瀏覽器請求--->Web服務器集群(Ngnix)--->應用服務器集群(Tomcat)--->文件/數據庫/緩存/消息隊列服務器集群
同時又可以玩分模塊,還可以按業務拆成一個個的小集群,為后面的架構升級做准備。
六、總之
前后端分離並非僅僅只是一種開發模式,而是一種架構模式(前后端分離架構)。千萬不要以為只有在擼代碼的時候把前端和后端分開就是前后端分離了,需要區分前后端項目。前端項目與后端項目是兩個項目,放在兩個不同的服務器,需要獨立部署,兩個不同的工程,兩個不同的代碼庫,不同的開發人員。
前后端工程師需要約定交互接口,實現並行開發,開發結束后需要進行獨立部署,前端通過ajax來調用http請求調用后端的Restful API。前端只需要關注頁面的樣式與動態數據的解析&渲染,而后端專注於具體業務邏輯。
七、最后,這里是拓展環節,一點建議(現在很多公司的前后端界限越來越明確,前端工程師只管前端的事情,后端工程師只管后端的事情,所以我覺得“術業有專攻”這句話,還是沒錯的)
對於后端Java工程師:
把精力放在Java基礎,設計模式,jvm原理,spring+springmvc原理及源碼,linux,mysql事務隔離與鎖機制,mongodb,http/tcp,多線程,分布式架構,彈性計算架構,微服務架構,Java性能優化,以及相關的項目管理等等。
后端追求的是:三高(高並發,高可用,高性能),安全,存儲,業務等等。
對於前端工程師:
把精力放在HTML5,CSS3,jQuery,AngularJS,Bootstrap,React.js,Vue.js,webpack,less/sass,gulp,Node.js,Google V8引擎,Javascript多線程,模塊化,面向切面編程,設計模式,瀏覽器兼容性,性能優化等等。
前端追求的是:頁面表現,速度流暢,兼容性,用戶體驗等等。
祝大家閱讀愉快~
作者:慕課網
鏈接:https://www.zhihu.com/question/28207685/answer/575863155
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。