天天看點

為什麼要前後端分離?

前戲

前後端分離已成為網際網路項目開發的業界标準使用方式,通過nginx+tomcat的方式(也可以中間加一個nodejs)有效的進行解耦, 并且前後端分離會為以後的大型分布式架構、彈性計算架構、微服務架構、多端化服務(多種用戶端,例如:浏覽器,車載終端,安卓,IOS等等)打下堅實的基礎。 這個步驟是系統架構從猿進化成人的必經之路。

核心思想是前端html頁面通過ajax調用後端的restuful api接口并使用json資料進行互動。

( 名詞解釋: 在網際網路架構中, web伺服器:一般指像nginx,apache這類的伺服器,他們一般隻能解析靜态資源。 應用伺服器:一般指像tomcat,jetty,resin這類的伺服器可以解析動态資源也可以解析靜态資源,但解析靜态資源的能力沒有web伺服器好。

一般都是隻有web伺服器才能被外網通路,應用伺服器隻能内網通路。 ) 術業有專攻(開發人員分離)

以前的JavaWeb項目大多數都是java程式員又當爹又當媽,又搞前端(ajax/jquery/js/html/css等等),又搞後端(java/mysql/oracle等等)。

随着時代的發展,漸漸的許多大中小公司開始把前後端的界限分的越來越明确,前端工程師隻管前端的事情,後端工程師隻管後端的事情。 正所謂術業有專攻,一個人如果什麼都會,那麼他畢竟什麼都不精。

大中型公司需要專業人才,小公司需要全才,但是對于個人職業發展來說,我建議是分開。

對于後端java工程師: 把精力放在java基礎,設計模式,jvm原理,spring+springmvc原理及源碼,linux,mysql事務隔離與鎖機制,mongodb,http/tcp,多線程,分布式架構(dubbo,dubbox,spring cloud),彈性計算架構,微服務架構(springboot+zookeeper+docker+jenkins),java性能優化,以及相關的項目管理等等。 後端追求的是:三高(高并發,高可用,高性能),安全,存儲,業務等等。

對于前端工程師: 把精力放在html5,css3,jquery,angularjs,bootstrap,reactjs,vuejs,webpack,less/sass,gulp,nodejs,Google V8引擎,javascript多線程,子產品化,面向切面程式設計,設計模式,浏覽器相容性,性能優化等等。 前端追求的是:頁面表現,速度流暢,相容性,使用者體驗等等。

術業有專攻,這樣你的核心競争力才會越來越高,正所謂你往生活中投入什麼,生活就會回報給你什麼。 并且兩端的發展都越來越高深,你想什麼都會,那你畢竟什麼都不精。

通過将team分成前後端team,讓兩邊的工程師更加專注各自的領域,獨立治理,然後建構出一個全棧式的精益求精的team。 原始人時代(各種耦合)

幾曾何時,我們的JavaWeb項目都是使用了若幹背景架構,springmvc/struts + spring + spring jdbc/hibernate/mybatis 等等。

大多數項目在java後端都是分了三層,控制層(controller/action),業務層(service/manage),持久層(dao)。 控制層負責接收參數,調用相關業務層,封裝資料,以及路由&渲染到jsp頁面。 然後jsp頁面上使用各種标簽(jstl/el/struts标簽等)或者手寫java表達式(<%=%>)将背景的資料展現出來,玩的是MVC那套思路。

我們先看這種情況:需求定完了,代碼寫完了,測試測完了,然後呢?要釋出了吧? 你需要用maven或者eclipse等工具把你的代碼打成一個war包,然後把這個war包釋出到你的生産環境下的web容器(tomcat/jboss/weblogic/websphere/jetty/resin)裡,對吧?

釋出完了之後,你要啟動你的web容器,開始提供服務,這時候你通過配置域名,dns等等相關,你的網站就可以通路了(假設你是個網站)。 那我們來看,你的前後端代碼是不是全都在那個war包裡?包括你的js,css,圖檔,各種第三方的庫,對吧?

好,下面在浏覽器中輸入你的網站域名(www.xxx.com),之後發生了什麼?(這個問題也是很多公司的面試題) 我撿幹的說了啊,基礎不好的童鞋請自己去搜。

浏覽器在通過域名通過dns伺服器找到你的伺服器外網ip,将http請求發送到你的伺服器,在tcp3次握手之後(http下面是tcp/ip),通過tcp協定開始傳輸資料,你的伺服器得到請求後,開始提供服務,接收參數,之後傳回你的應答給浏覽器,浏覽器再通過content-type來解析你傳回的内容,呈現給使用者。

那麼我們來看,我們先假設你的首頁中有100張圖檔,此時,使用者的看似一次http請求,其實并不是一次,使用者在第一次通路的時候,浏覽器中不會有緩存,你的100張圖檔,浏覽器要連着請求100次http請求(有人會跟我說http長連短連的問題,不在這裡讨論),你的伺服器接收這些請求,都需要耗費記憶體去建立socket來玩tcp傳輸(消耗你伺服器上的計算資源)。

重點來了,這樣的話,你的伺服器的壓力會非常大,因為頁面中的所有請求都是隻請求到你這台伺服器上,如果1個人還好,如果10000個人并發通路呢(先不聊伺服器叢集,這裡就說是單執行個體伺服器),那你的伺服器能扛住多少個tcp連接配接?你的帶寬有多大?你的伺服器的記憶體有多大?你的硬碟是高性能的嗎?你能抗住多少IO?你給web伺服器分的記憶體有多大?會不會當機?

這就是為什麼,越是大中型的web應用,他們越是要解耦。 理論上你可以把你的資料庫+應用服務+消息隊列+緩存+使用者上傳的檔案+日志+等等都扔在一台伺服器上,你也不用玩什麼服務治理,也不用做什麼性能監控,什麼報警機制等等,就亂成一鍋粥好了。 但是這樣就好像是你把雞蛋都放在一個籃子裡,隐患非常大。如果因為一個子應用的記憶體不穩定導緻整個伺服器記憶體溢出而hung住,那你的整個網站就挂掉了。

如果出意外挂掉,而恰好這時你們的業務又處于井噴式發展高峰期,那麼恭喜你,業務成功被技術卡住,很可能會流失大量使用者,後果不堪設想。 注意:技術一定是要走在業務前面的,否則你将錯過最佳的發展期喲,親~

此外,你的應用全部都耦合在一起,相當于一個巨石,當服務端負載能力不足時,一般會使用負載均衡的方式,将伺服器做成叢集,這樣其實你是在水準擴充一塊塊巨石,性能加速度會越來越低, 要知道,本身負載就低的功能or子產品是沒有必要水準擴充的,在本文中的例子就是你的性能瓶頸不在前端,那幹嘛要水準擴充前端呢??? 還有發版部署上線的時候,我明明隻改了後端的代碼,為什麼要前端也跟着釋出呢??? (引用:《架構探險-輕量級微服務架構》,黃勇)

正常的網際網路架構,是都要拆開的,你的web伺服器叢集,你的應用伺服器叢集+檔案伺服器叢集+資料庫伺服器叢集+消息隊列叢集+緩存叢集等等。 JSP的痛點

以前的javaWeb項目大多數使用jsp作為頁面層展示資料給使用者,因為流量不高,是以也沒有那麼苛刻的性能要求,但現在是大資料時代,對于網際網路項目的性能要求是越來越高, 是以原始的前後端耦合在一起的架構模式已經逐漸不能滿足我們,是以我們需要需找一種解耦的方式,來大幅度提升我們的負載能力。

1.動态資源和靜态資源全部耦合在一起,伺服器壓力大,因為伺服器會收到各種http請求,例如css的http請求,js的,圖檔的等等。 一旦伺服器出現狀況,前背景一起玩完,使用者體驗極差。

2.UI出好設計圖後,前端工程師隻負責将設計圖切成html,需要由java工程師來将html套成jsp頁面,出錯率較高(因為頁面中經常會出現大量的js代碼), 修改問題時需要雙方協同開發,效率低下。

3.jsp必須要在支援java的web伺服器裡運作(例如tomcat,jetty,resin等),無法使用nginx等(nginx據說單執行個體http并發高達5w,這個優勢要用上), 性能提不上來。

4.第一次請求jsp,必須要在web伺服器中編譯成servlet,第一次運作會較慢。

5.每次請求jsp都是通路servlet再用輸出流輸出的html頁面,效率沒有直接使用html高(是每次喲,親~)。

6.jsp内有較多标簽和表達式,前端工程師在修改頁面時會捉襟見肘,遇到很多痛點。

7.如果jsp中的内容很多,頁面響應會很慢,因為是同步加載。

8.需要前端工程師使用java的ide(例如eclipse),以及需要配置各種後端的開發環境,你們有考慮過前端工程師的感受嗎。

基于上述的一些痛點,我們應該把整個項目的開發權重往前移,實作前後端真正的解耦! 開發模式

以前老的方式是: 1.産品經曆/上司/客戶提出需求 2.UI做出設計圖 3.前端工程師做html頁面 4.後端工程師将html頁面套成jsp頁面( 前後端強依賴,後端必須要等前端的html做好才能套jsp。如果html發生變更,就更痛了,開發效率低) 5.內建出現問題 6.前端返工 7.後端返工 8.二次內建 9.內建成功 10.傳遞

新的方式是: 1.産品經曆/上司/客戶提出需求 2.UI做出設計圖 3.前後端約定接口&資料&參數 4.前後端并行開發( 無強依賴,可前後端并行開發,如果需求變更,隻要接口&參數不變,就不用兩邊都修改代碼,開發效率高) 5.前後端內建 6.前端頁面調整 7.內建成功 8.傳遞

請求方式

以前老的方式是: 1.用戶端請求 2.服務端的servlet或controller接收請求( 後端控制路由與渲染頁面,整個項目開發的權重大部分在後端) 3.調用service,dao代碼完成業務邏輯 4.傳回jsp 5.jsp展現一些動态的代碼

新的方式是: 1.浏覽器發送請求 2.直接到達html頁面( 前端 控制路由與渲染頁面 ,整個項目開發的權重前移) 3.html頁面負責調用服務端接口産生資料(通過ajax等等,背景傳回json格式資料,json資料格式因為簡潔高效而取代xml) 4.填充html,展現動态效果,在頁面上進行解析并操作DOM。 (有興趣的童鞋可以通路一下阿裡巴巴等大型網站,然後按一下F12,監控一下你重新整理一次頁面,他的http是怎麼玩的,大多數都是單獨請求背景資料, 使用json傳輸資料,而不是一個大而全的http請求把整個頁面包括動+靜全部傳回過來)

總結一下新的方式的請求步驟: 大量并發浏覽器請求--->web伺服器叢集(nginx)--->應用伺服器叢集(tomcat)--->檔案/資料庫/緩存/消息隊列伺服器叢集 同時又可以玩分子產品,還可以按業務拆成一個個的小叢集,為後面的架構更新做準備。

前後分離的優勢

1.可以實作真正的前後端解耦,前端伺服器使用nginx。 前端/WEB伺服器放的是css,js,圖檔等等一系列靜态資源(甚至你還可以css,js,圖檔等資源放到特定的檔案伺服器,例如阿裡雲的oss,并使用cdn加速),前端伺服器負責控制頁面引用&跳轉&路由,前端頁面異步調用後端的接口,後端/應用伺服器使用tomcat(把tomcat想象成一個資料提供者),加快整體響應速度。 (這裡需要使用一些前端工程化的架構比如nodejs,react,router,react,redux,webpack)

2.發現bug,可以快速定位是誰的問題,不會出現互相踢皮球的現象。 頁面邏輯,跳轉錯誤,浏覽器相容性問題,腳本錯誤,頁面樣式等問題,全部由前端工程師來負責。 接口資料出錯,資料沒有送出成功,應答逾時等問題,全部由後端工程師來解決。 雙方互不幹擾,前端與後端是相親相愛的一家人。

3.在大并發情況下,我可以同時水準擴充前後端伺服器,比如淘寶的一個首頁就需要2000+台前端伺服器做叢集來抗住日均多少億+的日均pv。 (去參加阿裡的技術峰會,聽他們說他們的web容器都是自己寫的,就算他單執行個體抗10萬http并發,2000台是2億http并發,并且他們還可以根據預知洪峰來無限拓展,很恐怖,就一個首頁。。。)

4.減少後端伺服器的并發/負載壓力 除了接口以外的其他所有http請求全部轉移到前端nginx上,接口的請求調用tomcat,參考nginx反向代理tomcat。 且除了第一次頁面請求外,浏覽器會大量調用本地緩存。

5.即使後端服務暫時逾時或者當機了,前端頁面也會正常通路,隻不過資料刷不出來而已。

6.也許你也需要有微信相關的輕應用,那樣你的接口完全可以共用,如果也有app相關的服務, 那麼隻要通過一些代碼重構,也可以大量複用接口,提升效率。(多端應用)

7.頁面顯示的東西再多也不怕,因為是異步加載。

8.nginx支援頁面熱部署,不用重新開機伺服器,前端更新更無縫。

9.增加代碼的維護性&易讀性(前後端耦在一起的代碼讀起來相當費勁)。

10.提升開發效率,因為可以前後端并行開發,而不是像以前的強依賴。

11.在nginx中部署證書,外網使用https通路,并且隻開放443和80端口,其他端口一律關閉(防止黑客端口掃描), 内網使用http,性能和安全都有保障。

12.前端大量的元件代碼得以複用,元件化,提升開發效率,抽出來! 注意事項

1.在開需求會議的時候,前後端工程師必須全部參加,并且需要制定好接口文檔,後端工程師要寫好測試用例(2個次元),不要讓前端工程師充當你的專職測試, 推薦使用chrome的插件postman或soapui或jmeter,service層的測試用例拿junit寫。ps:前端也可以玩單元測試嗎?

2.上述的接口并不是java裡的interface,說白了調用接口就是調用你controler裡的方法。

3.加重了前端團隊的工作量,減輕了後端團隊的工作量,提高了性能和可擴充性。

4.我們需要一些前端的架構來解決類似于頁面嵌套,分頁,頁面跳轉控制等功能。(上面提到的那些前端架構)。

5.如果你的項目很小,或者是一個單純的内網項目,那你大可放心,不用任何架構而言,但是如果你的項目是外網項目,呵呵哒。

6.以前還有人在使用類似于velocity/freemarker等模闆架構來生成靜态頁面,仁者見仁智者見智。

7.這篇文章主要的目的是說jsp在大型外網java web項目中被淘汰掉,可沒說jsp可以完全不學,對于一些學生朋友來說,jsp/servlet等相關的java web基礎還是要掌握牢的,不然你以為springmvc這種架構是基于什麼來寫的?

8.如果頁面上有一些權限等等相關的校驗,那麼這些相關的資料也可以通過ajax從接口裡拿。

9.對于既可以前端做也可以後端做的邏輯,我建議是放到前端,為什麼? 因為你的邏輯需要計算資源進行計算,如果放到後端去run邏輯,則會消耗帶寬&記憶體&cpu等等計算資源,你要記住一點就是 服務端的計算資源是有限的,而如果放到前端,使用的是用戶端的計算資源,這樣你的服務端負載就會下降(高并發場景)。 類似于資料校驗這種,前後端都需要做!

10.前端需要有機制應對後端請求逾時以及後端服務當機的情況,友好的展示給使用者。

擴充閱讀

1.其實對于js,css,圖檔這類的靜态資源可以考慮放到類似于阿裡雲的oss這類檔案伺服器上(如果是普通的伺服器&作業系統,存儲在到達pb級的檔案後,或者單個檔案夾内的檔案數量達到3-5萬, io會有很嚴重的性能問題), 再在oss上配cdn(全國子節點加速),這樣你頁面打開的速度像飛一樣, 無論你在全國的哪個地方,并且你的nginx的負載會進一步降低。

2.如果你要玩輕量級微服務架構,要使用nodejs做網關,用nodejs的好處還有利于seo優化,因為nginx隻是向浏覽器傳回頁面靜态資源,而國内的搜尋引擎爬蟲隻會抓取靜态資料,不會解析頁面中的js, 這使得應用得不到良好的搜尋引擎支援。同時因為nginx不會進行頁面的組裝渲染,需要把靜态頁面傳回到浏覽器,然後完成渲染工作,這加重了浏覽器的渲染負擔。 浏覽器發起的請求經過nginx進行分發,URL請求統一分發到nodejs,在nodejs中進行頁面組裝渲染;API請求則直接發送到後端伺服器,完成響應。

3.如果遇到跨域問題,spring4的CORS可以完美解決,但一般使用nginx反向代理都不會有跨域問題,除非你把前端服務和後端服務分成兩個域名。 JSONP的方式也被淘汰掉了。

4.如果想玩多端應用,注意要去掉tomcat原生的session機制,要使用token機制,使用緩存(因為是分布式系統),做單點,對于token機制的安全性問題,可以搜一下jwt。

5.前端項目中可以加入mock測試(構造虛拟測試對象來模拟後端,可以獨立開發和測試),後端需要有詳細的測試用例,保證服務的可用性與穩定性。 總結

前後端分離并非僅僅隻是一種開發模式,而是一種架構模式(前後端分離架構)。 千萬不要以為隻有在撸代碼的時候把前端和後端分開就是前後端分離了。需要區分前後端項目 前端項目與後端項目是兩個項目,放在兩個不同的伺服器,需要獨立部署,兩個不同的工程,兩個不同的代碼庫,不同的開發人員。 前後端工程師需要約定互動接口,實作并行開發,開發結束後需要進行獨立部署,前端通過ajax來調用http請求調用後端的restful api。

前端隻需要關注頁面的樣式與動态資料的解析&渲染,而後端專注于具體業務邏輯。

原文轉自http://blog.csdn.net/piantoutongyang/article/details/65446892