先後端分離已成爲互聯網項目開發的業界標準使用方式,經過Nginx+Tomcat的方式(也能夠中間加一個NodeJS)有效地對前端和後端的開發進行解耦。而且先後端分離會爲之後的大型分佈式架構、彈性計算架構、微服務架構、多端化服務(各類客戶端,好比瀏覽器、車載終端、安卓、IOS等)打下堅實的基礎。先後端分離的核心思想就是前端HTML頁面經過AJAX調用後端的RESTFUL API接口,並經過JSON數據進行交互。前端
前端的開發與後端的開發分離程序員
之前的JavaWeb項目,大多數都是Java程序員又搞前端,又搞後端。而隨着時代的發展,漸漸的許多大中小公司開始把先後端的界限分得愈來愈明確,即前端工程師只管前端的開發,後端工程師只管後端的開發。大中型公司須要專業的人才,小公司須要全才(省錢)。可是對於我的職業發展來講,仍是分開比較好,由於當生涯發展到後期的時候,企業每每要的是在某一方面上的專家,而不是熟練工。若是一我的前端後端都會一點,那也能夠說什麼都不會。數據庫
前端追求的是頁面的表現、速度的流暢、兼容性和用戶的體驗等。所以對於前端開發工程師來講,須要把精力放在HTML五、CSS三、JavaScript、jQuery、AngularJS、BootStrap、ReactJS、VueJS、Webpack、Less/Sass、Gulp、NodeJS、Google V8引擎、JS多線程、JS模塊化、JS面向切面編程、設計模式、瀏覽器兼容性、性能優化等上。編程
後端追求的是三高(高併發、高可用、高性能)、安全、存儲、業務等。所以對於後端開發工程師來講,須要把精力放在Java基礎、設計模式、JVM原理、Spring全家桶的原理及源碼、Linux、關係型數據庫事務隔離和鎖機制、MongoDB、HTTP/TCP、多線程、分佈式架構、彈性計算架構、微服務架構、Java性能優化、數據庫性能優化以及相關的項目管理等等。後端
往某個方向深深鑽研,這樣你的核心競爭力纔會愈來愈高。正所謂你往生活中投入什麼,生活就會反饋給你什麼。千萬別勉強本身去追求所謂的全棧,由於無論是前端和後端,到後期都有不少高深的東西讓你花費全部精力,你想什麼都會,最後可能什麼都不會(太貪心的人最後什麼都得不到,別信聖誕老人說的那句我全都要)。固然也不是說就不能去學,學也是能夠的,可是要偏重點,分清主次,就像人生不要把時間浪費在不值得的人和物身上同樣。設計模式
先後端分離解決的耦合問題前端工程化
曾幾什麼時候,咱們的JavaWeb項目都是使用了若干個後臺框架,好比Spring MVC、Structs、Spring Boot、Spring JDBC、Hibernate、MyBatis等。大多數項目在Java後端都是分了三層,即控制層(Controller)、業務層(Service)和持久層(Dao)。控制層負責接收參數,調用相關業務層,封裝數據,以及路由和渲染到JSP頁面(或模板頁面,如Freemarker)。而後JSP頁面上使用各類標籤或者手寫Java表達式將後臺的數據展示出來,玩的就是MVC那套思路。跨域
咱們先看這種狀況:咱們開發一個網站,需求定完了,代碼寫完了,測試跑完了,用Maven或IDE等工具把代碼打成一個war包完了,把war包發佈到生產環境下的WEB容器完了,啓動WEB容器完了,域名、DNS配置完了,網站就能夠訪問了。這時候,咱們的先後端代碼全都在那個war包裏了,包括JS、CSS、圖片等各類靜態資源文件。瀏覽器
接下來,咱們在瀏覽器中輸入網站域名(www.xxx.com),瀏覽器在經過域名和DNS服務器找到咱們的服務器外網IP,將HTTP請求發送到你的服務器,在TCP三次握手以後(HTTP下面是TCP/IP),經過TCP協議開始傳輸數據,咱們的服務器獲得請求後,開始提供服務,接收參數,以後返回咱們的應答給瀏覽器,瀏覽器再經過Content-type來解析返回的內容,呈現給用戶。緩存
這裏咱們假設咱們的首頁中有100張圖片,那麼當用戶訪問首頁的時候,就須要創建100個HTTP請求,咱們的服務器接收這些請求,都須要耗費內存去建立Socket來玩TCP傳輸(消耗服務器上的計算資源)。重點來了,這樣的話,咱們的服務器的壓力就會很是大,由於頁面中的全部請求都是隻請求到咱們的這臺服務器上,若是一我的還好,若是是有10000我的併發訪問呢(這裏先不說服務器集羣,就說單實例服務器),那麼咱們的服務器恐怕扛不住(TCP鏈接、帶寬、內存、硬盤、IO、WEB服務器的內存等方面),恐怕會宕機。
這就是爲何大中型的WEB應用要解耦的緣由。理論上咱們是能夠把數據庫、應用服務、消息隊列、緩存、用戶上傳的文件、日誌等都丟在一臺服務器上,也不用玩什麼服務治理,也不用作什麼性能監測,什麼報警機制等,愛宕機就宕機好了(佛系青年)。但是現實不容許咱們宕機啊,當某個子應用由於內存不穩定而致使整個服務器內存溢出,再而致使咱們的網站掛掉的時候,咱們就糟糕了。好比咱們公司的業務若是這時候正好處於井噴式發展的高峯期的時候,服務器掛掉了,業務就被技術卡住了,那麼就可能會致使大量用戶的流失,後果不堪設想。這裏順便提一句,技術必定要走在業務前面,不然可能會錯過最佳的發展期。
另外的,當你的應用全都耦合在一塊兒,就至關於一塊巨石,當服務器負載能力不足時,通常會使用負載均衡的方式,將服務器作成集羣。這樣其實你是在水平擴展一塊塊巨石,性能加速度會愈來愈低。要知道,自己負載就低的功能或模塊是沒有必要水平擴展的,水平擴展要針對性能瓶頸去擴展才對。在這裏的例子中,性能瓶頸跟前端沒有關係,沒有必要去水平擴展前端。同時,發版部署的時候,若是隻是改了後端的代碼,卻要前端代碼也跟着從新發布,顯然也下降了效率。
正由於這樣,正常的互聯網架構都是把WEB服務器集羣、應用服務器集羣、文件服務器集羣、數據庫服務器集羣、消息隊列集羣、緩存集羣等集羣拆分開的。
先後端耦合的缺點(以JSP爲例)
之前的JavaWeb項目大多數使用JSP做爲頁面層展現數據給用戶,由於流量不高,所以也沒有那麼苛刻的性能要求,但如今是大數據時代,對於互聯網項目的性能要求是愈來愈高,所以原始的先後端耦合在一塊兒的架構模式已經逐漸不能知足咱們,所以咱們須要找到一種解耦的方式,以大幅提高咱們的負載能力。先後端耦合主要有如下的缺點(以JSP爲例):
1.動態資源和靜態資源所有耦合在一塊兒,服務器壓力大,由於服務器會收到各類HTTP請求,例如CSS的HTTP請求,JS的,圖片的等等。一旦服務器出現情況,先後臺一塊兒完犢子,用戶體驗極差。若是先後端分離,你後端的服務器掛了,前端服務器沒掛,用戶仍然能夠看到界面,雖然請求不到數據,嘿嘿。
2.UI出好設計圖以後,前端開發工程師只負責將設計圖切成HTML,須要由Java開發工程師來將HTML套成JSP頁面,出錯率較高(由於頁面中常常會出現大量的JS代碼),修改問題的時候須要雙方協同開發,效率低下。
3.JSP頁面必需要在支持Java的WEB服務器上運行(如Tomcat、Jetty、Resin等),沒法使用Nginx等(官方宣稱單實例HTTP併發高達5W),性能提高不上來。
4.第一次請求JSP,必需要在WEB服務器中編譯成Servlet,第一次運行會較慢。而後以後的每次請求JSP都是訪問Servlet再用輸出流輸出的HTML頁面,效率沒有直接使用HTML高(注意是每次噢)。
5.JSP內有較多內置的專屬標籤和表達式,前端開發工程師在修改頁面時每每會撓頭撓到禿頭。
6.若是JSP中的內容不少,頁面響應會很慢,由於是同步加載,一次輸出全部內容。
7.修改JSP頁面須要前端開發工程師使用Java的IDE以及配置各類後端的開發環境,對前端開發工程師極不友好。
先後端分離的優勢
1.先後端分離能夠真正地實現先後端解耦,前端服務器使用Nginx。前端/WEB服務器放的是CSS、JS和圖片等一系列靜態資源(甚至能夠把這些靜態資源放到特定的文件服務器,如阿里雲的OSS,並使用CDN加速)。前端服務器負責控制頁面引用、跳轉和路由,前端頁面經過AJAX異步調用後端的接口,後端/應用服務器使用Tomcat(把風花雪月交給前端,只提供數據),加快總體響應數據。(這裏須要使用一些前端工程化的框架,如NodeJS、React、Router、Reudx、Webpack等)
2.先後端分離的模式下,若是發現Bug,能夠快速定位是誰的問題,不會出現互相踢皮球的現象。若是是頁面邏輯、跳轉錯誤、瀏覽器兼容性問題、腳本錯誤、頁面樣式等問題,統統是前端開發工程師的鍋。若是是接口數據出錯、數據提交失敗、應答超時等問題,則後端開發工程師應該挺身接鍋。雙方職責分明,就不會打架。
3.先後端分離在大併發的狀況下,咱們能夠同時水平擴展先後端服務器。要知道淘寶的一個首頁就須要2000+臺前端服務器作集羣來抗住日均多少億的日均PV。(阿里的技術峯會說到他們的WEB容器都是本身寫的,就算單實例抗10萬HTTP併發,2000臺是2億HTTP併發,而且他們還能夠根據預知洪峯來無限擴展,好恐怖啊,就一個首頁。。)
4.先後端分離能夠減小後端服務器的併發/負載壓力。除了接口之外的其餘全部HTTP請求所有轉移到前端Nginx上,接口的請求則轉發調用Tomcat。且除了第一次頁面請求外,瀏覽器會大量調用本地緩存去緩存頁面。
5.先後端分離的模式下,即便後端服務器暫時超時或宕機了,前端頁面也會正常訪問,只不過數據刷不出來而已。
6.先後端分離的模式下,後臺的接口能夠複用。好比須要作微信相關的輕應用,接口就徹底能夠共用,再好比說APP相關的服務,也能夠只經過一些代碼重構,就能夠大量複用接口,提高開發效率。(多端應用)
7.頁面顯示再多的內容也不怕了,由於從同步加載改爲了異步加載。
8.Nginx支持頁面的熱部署,不用重啓服務器,前端升級更無縫。
9.增長代碼的維護性和易讀性,提升開發效率(先後端代碼耦合在一塊兒很難讀,好比JSP頁面)。
10.先後端能夠並行開發,提升開發效率。
11.在Nginx中部署證書,外網使用HTTPS訪問,而且只開放443和80端口,其餘端口一概關閉(防止黑客端口掃描),內網使用HTTP,性能和安全都有保障。
先後端分離的注意事項
1.在開需求會議的時候,先後端工程師必須所有參加,而且須要制定好接口文檔,後端工程師要寫好測試用例(2個維度),不要讓前端工程師充當你的專職測試。
2.上述的接口並非Java裏的Interface,說白了調用接口就是調用你Controller裏面的方法。
3.咱們須要一些前端的框架來解決相似於頁面嵌套,分頁,頁面跳轉控制等功能。
4.小項目的話,好比單純的內網項目,就沒有必要先後端分離了,複雜架構反而會拖累性能。可是若是是大型外網項目,先後端分離就很是必要了。
5.之前還有人用相似於Velocity/Freemarker等框架模板生成靜態頁面,我的以爲和使用JSP其實也相差不遠,也就是性能好一點,沒有實現真正的先後端分離。
6.先後端分離會加劇前端團隊的工做量,減輕後端團隊的工做量,提升了性能和可擴展性。
7.若是頁面上有一些權限等等相關的校驗,這些相關的和數據也能夠經過AJAX從接口裏拿。
8.對於既能夠前端作又能夠後端作的邏輯,建議放在前端,由於邏輯計算時須要計算資源的,若是放到後端去運行邏輯,則會消耗帶寬、內存和CPU等等計算資源。你要記住一點就是服務端的計算資源是有限的,而若是放到前端,使用的是客戶端的計算資源,這樣你的服務端負載就會降低(高併發場景)。相似於數據校驗這種,先後端都須要作。
9.前端須要有機制應對後端請求超時以及後端服務宕機的狀況,友好地展現給客戶。
先後端分離的擴展閱讀
1.對於JS、CSS、圖片這類靜態資源能夠考慮放到相似於阿里雲的OSS這類文件服務器上(若是是普通的服務器和操做系統,存儲在到達PB級(1000TB)的文件後,或者單個文件夾內的文件數量達到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(JSON Web Token)。
5.前端項目中能夠加入mock測試(構造虛擬測試對象來模擬後端,能夠獨立開發和測試),後端則須要有詳細的測試用例,保證服務的可用性和穩定性。
總結
先後端分離並不是僅僅是一種開發模式,而是一種架構模式(先後端分離架構)。千萬不要覺得只有在寫代碼的時候把前端和後端分開就是先後端分離了,這樣的理解太片面了。先後端分離是須要區分先後端項目的,即前端項目和後端項目是兩個項目,放在兩個不一樣的服務器,須要獨立部署,兩個不一樣的工程,兩個不一樣的代碼庫,兩組不一樣的開發人員。先後端開發工程師須要約定交互的接口,實現並行開發。而在開發結束以後,前端項目和後端項目都須要進行獨立部署,前端經過AJAX來調用HTTP請求,調用後端的RESTFUL API。前端只須要關注頁面的樣式與動態數據的解析和渲染,不用關心數據是怎麼產生的;後端則專一於具體的業務邏輯,返回前端展示所須要的業務數據便可。
"不管去哪裏,都不要失去從新開始的勇氣。"