2021-05-12 14:32:11
新來的CTO禁止前後端分離,而且還說了一大堆優缺點!
1、背景
前後端分離已成為網際網路項目開發的業界標準使用方式,通過nginx+tomcat的方式(也可以中間加一個nodejs)有效的進行解耦,並且前後端分離會為以後的大型分散式架構、彈性計算架構、微服務架構、多端化服務(多種客戶端,例如:瀏覽器,車載終端,安卓,IOS等等)打下堅實的基礎。這個步驟是系統架構從猿進化成人的必經之路。
核心思想是前端HTML頁面通過AJAX呼叫後端的RESTFUL API介面並使用JSON資料進行互動。
Web伺服器:一般指像Nginx,Apache這類的伺服器,他們一般只能解析靜態資源;
應用伺服器:一般指像Tomcat,Jetty,Resin這類的伺服器可以解析動態資源也可以解析靜態資源,但解析靜態資源的能力沒有web伺服器好;
一般都是隻有web伺服器才能被外網訪問,應用伺服器只能內網訪問。
以前的Java Web項目大多數都是Java程式設計師又當爹又當媽,又搞前端,又搞後端。隨著時代的發展,漸漸的許多大中小公司開始把前後端的界限分的越來越明確,前端工程師只管前端的事情,後端工程師只管後端的事情。正所謂術業有專攻,一個人如果什麼都會,那麼他畢竟什麼都不精。大中型公司需要專業人才,小公司需要全才,但是對於個人職業發展來說,前後端需要分離。
2、未分離時代(各種耦合)
早期主要使用MVC框架,Jsp+Servlet的結構圖如下:
大致就是所有的請求都被髮送給作為控制器的Servlet,它接受請求,並根據請求資訊將它們分發給適當的JSP來響應。同時,Servlet還根據JSP的需求生成JavaBeans的例項並輸出給JSP環境。JSP可以通過直接呼叫方法或使用UseBean的自定義標籤得到JavaBeans中的資料。需要說明的是,這個View還可以採用 Velocity、Freemaker 等模板引擎。使用了這些模板引擎,可以使得開發過程中的人員分工更加明確,還能提高開發效率。
那麼,在這個時期,開發方式有如下兩種:
方式一
方式二
方式二已經逐漸淘汰。主要原因有兩點:1)前端在開發過程中嚴重依賴後端,在後端沒有完成的情況下,前端根本無法幹活;2)由於趨勢問題,會JSP,懂velocity,freemarker等模板引擎的前端越來越少;因此,方式二逐漸不被採用。然而,不得不說一點,方式一,其實很多小型傳統軟體公司至今還在使用。那麼,方式一和方式二具有哪些共同的缺點呢? 1、前端無法單獨偵錯,開發效率低;
2、 前端不可避免會遇到後臺程式碼,例如:
<body><% request.setCharacterEncoding("utf-8") String name=request.getParameter("username"); out.print(name); %></body>
這種方式耦合性太強。那麼,就算你用了freemarker等模板引擎,不能寫Java程式碼。那前端也不可避免的要去重新學習該模板引擎的模板語法,無謂增加了前端的學習成本。正如我們後端開發不想寫前端一樣,你想想如果你的後臺程式碼裡嵌入前端程式碼,你是什麼感受?因此,這種方式十分不妥。
3、JSP本身所導致的一些其他問題 比如,JSP第一次運行的時候比較緩慢,因為裡頭包含一個將JSP翻譯為Servlet的步驟。再比如因為同步載入的原因,在JSP中有很多內容的情況下,頁面響應會很慢。
3、半分離時代
前後端半分離,前端負責開發頁面,通過介面(Ajax)獲取資料,採用Dom操作對頁面進行資料繫結,最終是由前端把頁面渲染出來。這也就是Ajax與SPA應用(單頁應用)結合的方式,其結構圖如下:
步驟如下:(1)瀏覽器請求,CDN返回HTML頁面;(2)HTML中的JS程式碼以Ajax方式請求後臺的Restful介面;(3)介面返回Json資料,頁面解析Json資料,通過Dom操作渲染頁面;後端提供的都是以JSON為資料格式的API介面供Native端使用,同樣提供給WEB的也是JSON格式的API介面。
那麼意味著WEB工作流程是:1、開啟web,載入基本資源,如CSS,JS等;2、發起一個Ajax請求再到服務端請求資料,同時展示loading;3、得到json格式的資料後再根據邏輯選擇模板渲染出DOM字元串;4、將DOM字元串插入頁面中web view渲染出DOM結構;這些步驟都由使用者所使用的裝置中逐步執行,也就是說使用者的裝置效能與APP的運行速度聯絡的更緊換句話說就是如果使用者的裝置很低端,那麼APP開啟頁面的速度會越慢。
為什麼說是半分離的?因為不是所有頁面都是單頁面應用,在多頁面應用的情況下,前端因為沒有掌握controller層,前端需要跟後端討論,我們這個頁面是要同步輸出呢,還是非同步Json渲染呢?而且,即使在這一時期,通常也是一個工程師搞定前後端所有工作。因此,在這一階段,只能算半分離。
首先,這種方式的優點是很明顯的。前端不會嵌入任何後臺程式碼,前端專注於HTML、CSS、JS的開發,不依賴於後端。自己還能夠模擬Json資料來渲染頁面。發現Bug,也能迅速定位出是誰的問題。
然而,在這種架構下,還是存在明顯的弊端的。最明顯的有如下幾點:1)JS存在大量冗餘,在業務複雜的情況下,頁面的渲染部分的程式碼,非常複雜;2)在Json返回的資料量比較大的情況下,渲染的十分緩慢,會出現頁面卡頓的情況;3)SEO( Search Engine Optimization,即搜尋引擎優化)非常不方便,由於搜尋引擎的爬蟲無法爬下JS非同步渲染的資料,導致這樣的頁面,SEO會存在一定的問題;4)資源消耗嚴重,在業務複雜的情況下,一個頁面可能要發起多次HTTP請求才能將頁面渲染完畢。可能有人不服,覺得PC端建立多次HTTP請求也沒啥。那你考慮過移動端麼,知道移動端建立一次HTTP請求需要消耗多少資源麼?
正是因為如上缺點,我們才亟需真正的前後端分離架構。
4、分離時代
大家一致認同的前後端分離的例子就是SPA(Single-page application),所有用到的展現資料都是後端通過非同步介面(AJAX/JSONP)的方式提供的,前端只管展現。從某種意義上來說,SPA確實做到了前後端分離,但這種方式存在兩個問題:
WEB服務中,SPA類佔的比例很少。很多場景下還有同步/同步+非同步混合的模式,SPA不能作為一種通用的解決方案;現階段的SPA開發模式,介面通常是按照展現邏輯來提供的,而且為了提高效率我們也需要後端幫我們處理一些展現邏輯,這就意味著後端還是涉足了view層的工作,不是真正的前後端分離。SPA式的前後端分離,從物理層做區分(認為只要是客戶端的就是前端,伺服器端就是後端)這種分法已經無法滿足前後端分離的需求,我們認為從職責上劃分才能滿足目前的使用場景:
前端負責view和controller層 後端只負責model層,業務處理與資料持久化等 controller層與view層對於目前的後端開發來說,只是很邊緣的一層,目前的java更適合做持久層、model層的業務。
在前後端徹底分離這一時期,前端的範圍被擴展,controller層也被認為屬於前端的一部分。在這一時期:前端:負責View和Controller層。後端:只負責Model層,業務/資料處理等。
可是服務端人員對前端HTML結構不熟悉,前端也不懂後臺程式碼呀,controller層如何實現呢?這就是node.js的妙用了,node.js適合運用在高併發、I/O密集、少量業務邏輯的場景。最重要的一點是,前端不用再學一門其他的語言了,對前端來說,上手度大大提高。
可以就把Nodejs當成跟前端互動的api。總得來說,NodeJs的作用在MVC中相當於C(控制器)。Nodejs路由的實現邏輯是把前端靜態頁面程式碼當成字元串傳送到客戶端(例如瀏覽器),簡單理解可以理解為路由是提供給客戶端的一組api介面,只不過返回的資料是頁面程式碼的字元串而已。
用NodeJs來作為橋樑架接伺服器端API輸出的JSON。後端出於效能和別的原因,提供的介面所返回的資料格式也許不太適合前端直接使用,前端所需的排序功能、篩選功能,以及到了檢視層的頁面展現,也許都需要對介面所提供的資料進行二次處理。這些處理雖可以放在前端來進行,但也許資料量一大便會浪費瀏覽器效能。因而現今,增加Node中間層便是一種良好的解決方案。
瀏覽器(webview)不再直接請求JSP的API,而是:1)瀏覽器請求伺服器端的NodeJS;2)NodeJS再發起HTTP去請求JSP;3)JSP依然原樣API輸出JSON給NodeJS;4)NodeJS收到JSON後再渲染出HTML頁面;5)NodeJS直接將HTML頁面flush到瀏覽器;這樣,瀏覽器得到的就是普通的HTML頁面,而不用再發Ajax去請求伺服器了。
淘寶的前端團隊提出的中途島(Midway Framework)的架構如下圖所示:
增加node.js作為中間層,具體有哪些好處呢?
(1)適配性提升;我們其實在開發過程中,經常會給PC端、mobile、app端各自研發一套前端。其實對於這三端來說,大部分端業務邏輯是一樣的。唯一區別就是互動展現邏輯不同。如果controller層在後端手裡,後端為了這些不同端頁面展示邏輯,自己維護這些controller,模版無法重用,徒增和前端溝通端成本。如果增加了node.js層,此時架構圖如下:
在該結構下,每種前端的介面展示邏輯由node層自己維護。如果產品經理中途想要改動介面什麼的,可以由前端自己專職維護,後端無需操心。前後端各司其職,後端專注自己的業務邏輯開發,前端專注產品效果開發。
(2)響應速度提升;我們有時候,會遇到後端返回給前端的資料太簡單了,前端需要對這些資料進行邏輯運算。那麼在資料量比較小的時候,對其做運算分組等操作,並無影響。但是當資料量大的時候,會有明顯的卡頓效果。這時候,node中間層其實可以將很多這樣的程式碼放入node層處理、也可以替後端分擔一些簡單的邏輯、又可以用模板引擎自己掌握前臺的輸出。這樣做靈活度、響應度都大大提升。
舉個例子,即使做了頁面靜態化之後,前端依然還是有不少需要實時從後端獲取的資訊,這些資訊都在不同的業務系統中,所以需要前端傳送5、6個非同步請求來。有了NodeJs之後,前端可以在NodeJs中去代理這5個非同步請求。還能很容易的做bigpipe,這塊的優化能讓整個渲染效率提升很多。在PC上你覺得發5、6個非同步請求也沒什麼,但是在無線端,在客戶手機上建立一個http請求開銷很大。有了這個優化,效能一下提升好幾倍。
(3)效能得到提升;大家應該都知道單一職責原則。從該角度來看,我們,請求一個頁面,可能要響應很多個後端介面,請求變多了,自然速度就變慢了,這種現象在mobile端更加嚴重。採用node作為中間層,將頁面所需要的多個後端資料,直接在內網階段就拼裝好,再統一返回給前端,會得到更好的效能。
(4)非同步與模板統一;淘寶首頁就是被幾十個HTML片段(每個片段一個檔案)拼裝成,之前PHP同步include這幾十個片段,一定是序列的,Node可以非同步,讀檔案可以並行,一旦這些片段中也包含業務邏輯,非同步的優勢就很明顯了,真正做到哪個檔案先渲染完就先輸出顯示。前端機的檔案系統越複雜,頁面的組成片段越多,這種非同步的提速效果就越明顯。前後端模板統一在無線領域很有用,PC頁面和WIFI場景下的頁面適合前端渲染(後端資料Ajax到前端),2G、3G弱網路環境適合後端渲染(資料隨頁面吐給前端),所以同樣的模板,在不同的條件下走不同的渲染渠道,模板只需一次開發。
增加NodeJS中間層後的前後端職責劃分:
5、總結
從經典的JSP+Servlet+JavaBean的MVC時代,到SSM(Spring + SpringMVC + Mybatis)和SSH(Spring + Struts + Hibernate)的Java 框架時代,再到前端框架(KnockoutJS、AngularJS、vueJS、ReactJS)為主的MV*時代,然後是Nodejs引領的全棧時代,技術和架構一直都在進步。雖然「基於NodeJS的全棧式開發」模式很讓人興奮,但是把基於Node的全棧開發變成一個穩定,讓大家都能接受的東西還有很多路要走。創新之路不會止步,無論是前後端分離模式還是其他模式,都是為了更方便得解決需求,但它們都只是一個「中轉站」。前端項目與後端項目是兩個項目,放在兩個不同的伺服器,需要獨立部署,兩個不同的工程,兩個不同的程式碼庫,不同的開發人員。前端只需要關注頁面的樣式與動態資料的解析及渲染,而後端專注於具體業務邏輯。
相關文章