前后端分離,不分離簡介


前后端分離,不分離簡介 前言 前后端分離已成為互聯網項目開發的業界標准使用方式,通過nginx+tomcat的方式(也可以中間加一個nodejs)有效的進行解耦,並且前后端分離會為以后的大型分布式架構" />
<meta property="og:description" content="前后端分離,不分離簡介 前言 前后端分離已成為互聯網項目開發的業界標准使用方式,通過nginx&#x2B;tomcat的方式(也可以中間加一個nodejs)有效的進行解耦,並且前后端分離會為以后的大型分布式架構" />

<p>前后端分離已成為互聯網項目開發的業界標准使用方式,通過nginx+tomcat的方式(也可以中間加一個nodejs)有效的進行解耦,並且前后端分離會為以后的大型分布式架構、彈性計算架構、微服務架構、多端化服務(多種客戶端,例如:瀏覽器,車載終端,安卓,IOS等等)打下堅實的基礎。這個步驟是系統架構從猿進化成人的必經之路。
核心思想是前端html頁面通過ajax調用后端的restuful api接口並使用json數據進行交互。</code></p>
名詞解釋
Web服務器
一般指像Nginx,apache這類的服務器,他們一般只能解析靜態資源.
應用服務器
一般指像tomcat,jetty,resin這類的服務器可以解析動態資源也可以解析靜態資源,但解析靜態資源能力沒有web服務器好.

未分離時代各種耦合">未分離時代(各種耦合)
早期主要使用MVC框架,Jsp+Servlet的結構圖如下

大致就是所有的請求都被發送給作為控制器的Servlet,它接受請求,並根據請求信息將它們分發給適當的JSP來響應。同時,Servlet還根據JSP的需求生成JavaBeans的實例並輸出給JSP環境。JSP可以通過直接調用方法或使用UseBean的自定義標簽得到JavaBeans中的數據。需要說明的是,這個View還可以采用 Velocity、Freemaker 等模板引擎。使用了這些模板引擎,可以使得開發過程中的人員分工更加明確,還能提高開發效率。
那么,在這個時期,開發方式有如下兩種:
方式一

方式二
方式二已經逐漸淘汰。主要原因有兩點:
1)前端在開發過程中嚴重依賴后端,在后端沒有完成的情況下,前端根本無法干活;
2)由於趨勢問題,會JSP,懂velocity,freemarker等模板引擎的前端越來越少;
因此,方式二逐漸不被采用。然而,不得不說一點,方式一,其實很多小型傳統軟件公司至今還在使用。那么,方式一和方式二具有哪些共同的缺點呢?
1、前端無法單獨調試,開發效率低;
2、 前端不可避免會遇到后台代碼,例如:

/* 1)前端在開發過程中嚴重依賴后端,在后端沒有完成的情況下,前端根本無法干活;
2)由於趨勢問題,會JSP,懂velocity,freemarker等模板引擎的前端越來越少;
因此,方式二逐漸不被采用。然而,不得不說一點,方式一,其實很多小型傳統軟件公司至今還在使用。那么,方式一和方式二具有哪些共同的缺點呢?
1、前端無法單獨調試,開發效率低;
2、 前端不可避免會遇到后台代碼,
例如:
*/ <body>
<%
request.setCharacterEncoding("utf-8")
String name=request.getParameter("username") ;
out.print(name);
%> </body>這種方式耦合性太強。那么,就算你用了freemarker等模板引擎,不能寫Java代碼。那前端也不可避免的要去重新學習該模板引擎的模板語法,無謂增加了前端的學習成本。正如我們后端開發不想寫前端一樣,你想想如果你的后台代碼里嵌入前端代碼,你是什么感受?因此,這種方式十分不妥。</p>3、JSP本身所導致的一些其他問題 比如,JSP第一次運行的時候比較緩慢,因為里頭包含一個將JSP翻譯為Servlet的步驟。再比如因為同步加載的原因,在JSP中有很多內容的情況下,頁面響應會很慢。


前后端未分離


在前后端不分離架構中,所有的靜態資源和業務代碼統一部署在同一台服務器上。服務器接收到瀏覽器的請求后,進行處理得到數據,然后將數據填充到靜態頁面中,最終返回給瀏覽器。
半分離時代
前后端半分離,前端負責開發頁面,通過接口(Ajax)獲取數據,采用Dom操作對頁面進行數據綁定,最終是由前端把頁面渲染出來。這也就是Ajax與SPA應用(單頁應用)結合的方式,其結構圖如下:

步驟如下
(1)瀏覽器請求,CDN返回HTML頁面;
(2)HTML中的JS代碼以Ajax方式請求后台的Restful接口;
(3)接口返回Json數據,頁面解析Json數據,通過Dom操作渲染頁面;
*/

后端提供的都是以JSON為數據格式的API接口供Native端使用,同樣提供給WEB的也是JSON格式的API接口。</p>
那么意味着Web工作流程是

1、打開web,加載基本資源,如CSS,JS等;
2、發起一個Ajax請求再到服務端請求數據,同時展示loading;
3、得到json格式的數據后再根據邏輯選擇模板渲染出DOM字符串;
4、將DOM字符串插入頁面中web view渲染出DOM結構;
*/
這些步驟都由用戶所使用的設備中逐步執行,也就是說用戶的設備性能與APP的運行速度聯系的更緊換句話說就是如果用戶的設備很低端,那么APP打開頁面的速度會越慢。
為什么說是半分離的?因為不是所有頁面都是單頁面應用,在多頁面應用的情況下,前端因為沒有掌握controller層,前端需要跟后端討論,我們這個頁面是要同步輸出呢,還是異步Json渲染呢?而且,即使在這一時期,通常也是一個工程師搞定前后端所有工作。因此,在這一階段,只能算半分離。</p>
首先,這種方式的優點是很明顯的。前端不會嵌入任何后台代碼,前端專注於HTML、CSS、JS的開發,不依賴於后端。自己還能夠模擬Json數據來渲染頁面。發現Bug,也能迅速定位出是誰的問題。
 然而,在這種架構下,還是存在明顯的弊端的。最明顯的有如下幾點:
1)JS存在大量冗余,在業務復雜的情況下,頁面的渲染部分的代碼,非常復雜;
2)在Json返回的數據量比較大的情況下,渲染的十分緩慢,會出現頁面卡頓的情況;
3)SEO( Search Engine Optimization,即搜索引擎優化)非常不方便,由於搜索引擎的爬蟲無法爬下JS異步渲染的數據,導致這樣的頁面,SEO會存在一定的問題;
4)資源消耗嚴重,在業務復雜的情況下,一個頁面可能要發起多次HTTP請求才能將頁面渲染完畢。可能有人不服,覺得PC端建立多次HTTP請求也沒啥。那你考慮過移動端么,知道移動端建立一次HTTP請求需要消耗多少資源么?
前后端分離
大家一致認同的前后端分離的例子就是SPA(Single-page application),所有用到的展現數據都是后端通過異步接口(AJAX/JSONP)的方式提供的,前端只管展現。從某種意義上來說,SPA確實做到了前后端分離,但這種方式存在兩個問題:
WEB服務中,SPA類占的比例很少。很多場景下還有同步/同步+異步混合的模式,SPA不能作為一種通用的解決方案;</li>
現階段的SPA開發模式,接口通常是按照展現邏輯來提供的,而且為了提高效率我們也需要后端幫我們處理一些展現邏輯,這就意味着后端還是涉足了view層的工作,不是真正的前后端分離。
SPA式的前后端分離,從物理層做區分(認為只要是客戶端的就是前端,服務器端就是后端)這種分法已經無法滿足前后端分離的需求,我們認為從職責上划分才能滿足目前的使用場景:
前端負責view和controller層
后端只負責model層,業務處理與數據持久化等
*/
層與view層對於目前的后端開發來說,只是很邊緣的一層,目前的java更適合做持久層、model層的業務。
在前后端徹底分離這一時期,前端的范圍被擴展,controller層也被認為屬於前端的一部分。在這一時期:

前端:負責View和Controller層。
后端:只負責Model層,業務/數據處理等。
可是服務端人員對前端HTML結構不熟悉,前端也不懂后台代碼呀,controller層如何實現呢?這就是node.js的妙用了,node.js適合運用在高並發、I/O密集、少量業務邏輯的場景。最重要的一點是,前端不用再學一門其他的語言了,對前端來說,上手度大大提高。

可以就把Nodejs當成跟前端交互的api。總得來說,NodeJs的作用在MVC中相當於C(控制器)。Nodejs路由的實現邏輯是把前端靜態頁面代碼當成字符串發送到客戶端(例如瀏覽器),簡單理解可以理解為路由是提供給客戶端的一組api接口,只不過返回的數據是頁面代碼的字符串而已。
<p>用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)的架構如下圖所示:



*/1. 服務器一分為二,前后端分別部署,靜態資源放在前端服務器,業務代碼放在后端服務器.

2. 前端服務器需要接受http請求 (一般使用node.js)
3. 前端服務器需要進行視圖解析 (一般使用vue.js,angular.js)
4. 前端服務器需要處理路由 (也就是頁面之間的跳轉邏輯)
5. 后端服務器只需要返回數據.
*/
"前后端分離的模板探索
做前后端分離時,第一個關注的問題就是渲染, 也就是view這個層面工作
在傳統的開發模式中,瀏覽器端與服務器端是由不同的前后端兩個團隊開發,但是模版卻又在這兩者中間的模糊地帶。因此模版上面總不可避免的越來越多復雜邏輯,最終難以維護。</p>
我們選擇了NodeJS,作為一個前后端的中間層。試圖藉由NodeJS,來疏理 <strong>View</strong> 層面的工作。
使得前后端分工更明確,讓專案更好維護,達成更好的用戶體驗。
渲染這塊工作,對於前端開發者的日常工作來說,佔了非常大的比例,也是最容易與后端開發糾結不清的地方。
回首過去前端技術發展的這幾年, <strong>View</strong> 這個層面的工作,經過了許多次的變革,像是:
1. Form Submit 全頁刷新 =&gt; Ajax局部刷新
2. 服務端渲染 + mvc =&gt; 客戶端渲染 + mvc
3. 傳統換頁跳轉 =&gt; 單頁面應用
可以觀察到在這幾年,大家都傾向將 渲染 這件事,從服務器端端移向了瀏覽器端。
而服務器端則專注於 服務化 ,提供數據接口。
瀏覽器端渲染的好處
1.擺脫業務邏輯與呈現邏輯在Java模版引擎中的耦合與混亂。
2.針對多終端應用,更容易以接口化的形式。在瀏覽器端搭配不同的模版,呈現不同的應用。
3.頁面呈現本來就不僅是html,在前端的渲染可以更輕易的以組件化形式 (html + js + css)提供功能,使得前端組件不需依賴於服務端產生的html結構。
4.脫離對於后端開發、發佈流程的依賴。
5.方便聯調。
瀏覽器端渲染的壞處
但是在享受好處的同時,我們同樣的也面臨了 瀏覽器端渲染 所帶來的壞處,像是:
1.模版分離在不同的庫。有的模版放在服務端 (JAVA),而有的放在瀏覽器端 (JS)。前后端模版語言不相通。
2.需要等待所有模版與組件在瀏覽器端載入完成后才能開始渲染,無法即開即看。
3.首次進入會有白屏等待渲染的時間,不利於用戶體驗
4.開發單頁面應用時,前端Route與服務器端Route不匹配,處理起來很麻煩。
5.重要內容都在前端組裝,不利於SEO
增加nodejs中間層好處
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作為中間層,將頁面所需要的多個后端數據,直接在內網階段就拼裝好,再統一返回給前端,會得到更好的性能。</p>
<p>4.異步與模板統一;淘寶首頁就是被幾十個HTML片段(每個片段一個文件)拼裝成,之前PHP同步include這幾十個片段,一定是串行的,Node可以異步,讀文件可以並行,一旦這些片段中也包含業務邏輯,異步的優勢就很明顯了,真正做到哪個文件先渲染完就先輸出顯示。前端機的文件系統越復雜,頁面的組成片段越多,這種異步的提速效果就越明顯。前后端模板統一在無線領域很有用,PC頁面和WIFI場景下的頁面適合前端渲染(后端數據Ajax到前端),2G、3G弱網絡環境適合后端渲染(數據隨頁面吐給前端),所以同樣的模板,在不同的條件下走不同的渲染渠道,模板只需一次開發。
增加nodejs中間層的前后端職責划分

前后端分離技術分工">前后端分離技術分工
以前的JavaWeb項目大多數都是java程序員又當爹又當媽,又搞前端,又搞后端。
隨着時代的發展,漸漸的許多大中小公司開始把前后端的界限分的越來越明確,前端工程師只管前端的事情,后端工程師只管后端的事情。正所謂術業有專攻,一個人如果什么都會,那么他畢竟什么都不精。大中型公司需要專業人才,小公司需要全才,但是對於個人職業發展來說,我建議是分開。
對於后端java工程師">對於后端java工程師
負責Model層, 業務處理/數據等
把精力放在java基礎,設計模式,jvm原理,spring+springmvc原理及源碼,linux,mysql事務隔離與鎖機制,mongodb,http/tcp,多線程,分布式架構,彈性計算架構,微服務架構,java性能優化,以及相關的項目管理等等。
后端追求的是:三高(高並發,高可用,高性能),安全,存儲,業務等等。
對於前段工程師">對於前段工程師
負責view和controller層

把精力放在html5,css3,jquery,angularjs,bootstrap,reactjs,vuejs,webpack,less/sass,gulp,nodejs,Google V8引擎,javascript多線程,模塊化,面向切面編程,設計模式,瀏覽器兼容性,性能優化等等。

前端追求的是: 頁面表現,速度流暢,兼容性,用戶體驗等等。
術業有專攻,這樣你的核心競爭力才會越來越高,正所謂你往生活中投入什么,生活就會反饋給你什么。並且兩端的發展都越來越高深,你想什么都會,那你畢竟什么都不精。通過將team分成前后端team,讓兩邊的工程師更加專注各自的領域,獨立治理,然后構建出一個全棧式的精益求精的team。開發模式不分離方式產品經歷/領導/客戶提出需求=<mark>》UI做出設計圖 =<mark>》前端工程師做html頁面</mark>=》后端工程師將html頁面套成jsp頁面(前后端強依賴,后端必須要等前端的html做好才能套jsp。如果html發生變更,就更痛了,開發效率低)</mark>=》集成出現問題 ===》前端返工 =<mark>》后端返工</mark>=》二次集成 ===》集成成功 ==》交付分離方式 產品經歷/領導/客戶提出需===》UI做出設計圖 ===》前后端約定接口&amp;數據&amp;參數 =<mark>》前后端並行開發(無強依賴,可前后端並行開發,如果需求變更,只要接口&amp;參數不變,就不用兩邊都修改代碼,開發效率高)</mark>=》前后端集成 ===》前端頁面調整 ===》集成成功 ===》交付.

請求方式">請求方式
"不分離方式-2
1. 客戶端請求
2. 服務端的servlet或controller接受請求 (后端控制路由與渲染頁面,整個項目開發的權重大部分在后端)
3. 調用service,dao代碼完成代碼邏輯
4. 返回jsp
5. jsp展現一些動態的代碼
*/
分離方式-2

1. 瀏覽器發送請求
2. 直接到達html頁面(前端控制路由與渲染頁面,整個項目開發的權重前移)
3. html頁面負責調用服務端接口產生數據(通過ajax等等, 后台返回json格式數據,json數據格式因為簡介高效取代xml).
4. 填充html,展現動態效果,在頁面進行解析並操作DOM.
*/

大量並發瀏覽器請求 ---&gt; web服務器集群(nginx) ---&gt; 應用服務器集群(tomcat),文件/數據庫/緩存/消息隊列服務器集群同時又可以玩分模塊,還可以按業務拆成一個個的小集群,為后面的架構升級做准備<
前后端分離優勢
可以實現真正的前后端解耦">可以實現真正的前后端解耦

前端服務器使用nginx。前端/WEB服務器放的是css,js,圖片等等一系列靜態資源(甚至你還可以css,js,圖片等資源放到特定的文件服務器,例如阿里雲的oss,並使用cdn加速),前端服務器負責控制頁面引用&amp;跳轉&amp;路由,前端頁面異步調用后端的接口,后端/應用服務器使用tomcat(把tomcat想象成一個數據提供者),加快整體響應速度。(這里需要使用一些前端工程化的框架比如nodejs,react,router,react,redux,webpack)

發現bug

發現bug,可以快速定位是誰的問題,不會出現互相踢皮球的現象。頁面邏輯,跳轉錯誤,瀏覽器兼容性問題,腳本錯誤,頁面樣式等問題,全部由前端工程師來負責。接口數據出錯,數據沒有提交成功,應答超時等問題,全部由后端工程師來解決。雙方互不干擾,前端與后端是相親相愛的一家人。
大並發情況可以水平擴展前后端服務器">大並發情況可以水平擴展前后端服務器
在大並發情況下,我可以同時水平擴展前后端服務器,比如淘寶的一個首頁就需要2000+台前端服務器做集群來抗住日均多少億+的日均pv。(去參加阿里的技術峰會,聽他們說他們的web容器都是自己寫的,就算他單實例抗10萬http並發,2000台是2億http並發,並且他們還可以根據預知洪峰來無限拓展,很恐怖,就一個首頁。。。)
減少后端服務器的並發負載壓力">減少后端服務器的並發/負載壓力
減少后端服務器的並發/負載壓力。除了接口以外的其他所有http請求全部轉移到前端nginx上,接口的請求調用tomcat,參考nginx反向代理tomcat。且除了第一次頁面請求外,瀏覽器會大量調用本地緩存。

及時后端服務器暫時超時或者宕機前端頁面也會正常訪問只不過數據刷不出來而已">及時后端服務器暫時超時或者宕機,前端頁面也會正常訪問,只不過數據刷不出來而已
多端應用">多端應用
也許你也需要有微信相關的輕應用,那樣你的接口完全可以共用,如果也有app相關的服務,那么只要通過一些代碼重構,也可以大量復用接口,提升效率。(多端應用)

頁面顯示的東西再多也不怕因為是異步加載">頁面顯示的東西再多也不怕,因為是異步加載.
nginx支持頁面熱部署不用重啟服務器前端升級更無縫">nginx支持頁面熱部署,不用重啟服務器,前端升級更無縫
增加代碼的維護性易讀性">增加代碼的維護性&amp;易讀性
前后端耦在一起的代碼讀起來相當費勁</code>
提升開發效率"
因為可以前后端並行開發,而不是像以前的強依賴

在nginx中部署證書外網https訪問只開放443和80其他端口一律關閉(防止黑客端口掃描),內網使用http,性能和安全都有保障">在nginx中部署證書,外網https訪問,只開放443和80,其他端口一律關閉(防止黑客端口掃描),內網使用http,性能和安全都有保障
前端大量的組件代碼得以復用,組件化,提升開發效率,抽出來">前端大量的組件代碼得以復用,組件化,提升開發效率,抽出來</h5>
前后端分離注意事項">前后端分離注意事項
1.在開需求會議的時候,前后端工程師必須全部參加,並且需要制定好接口文檔,后端工程師要寫好測試用例(2個維度),不要讓前端工程師充當你的專職測試,推薦使用chrome的插件postman或soapui或jmeter,service層的測試用例拿junit寫。ps:前端也可以玩單元測試嗎?
2.上述的接口並不是java,go里的interface,說白了調用接口就是調用你controler里的方法。
3.加重了前端團隊的工作量,減輕了后端團隊的工作量,提高了性能和可擴展性。
4.我們需要一些前端的框架來解決類似於頁面嵌套,分頁,頁面跳轉控制等功能。(上面提到的那些前端框架).
5.如果你的項目很小,或者是一個單純的內網項目,那你大可放心,不用任何架構而言,但是如果你的項目是外網項目...
6.以前還有人在使用類似於velocity/freemarker等模板框架來生成靜態頁面,仁者見仁智者見智。
7.這篇文章主要的目的是說jsp在大型外網java web項目中被淘汰掉,可沒說jsp可以完全不學,對於一些學生朋友來說,jsp/servlet等相關的java web基礎還是要掌握牢的,不然你以為springmvc這種框架是基於什么來寫的?
8.如果頁面上有一些權限等等相關的校驗,那么這些相關的數據也可以通過ajax從接口里拿。
9.對於既可以前端做也可以后端做的邏輯,我建議是放到前端,為什么?因為你的邏輯需要計算資源進行計算,如果放到后端去run邏輯,則會消耗帶寬&amp;內存&amp;cpu等等計算資源,你要記住一點就是服務端的計算資源是有限的,而如果放到前端,使用的是客戶端的計算資源,這樣你的服務端負載就會下降(高並發場景)。類似於數據校驗這種,前后端都需要做!
10.前端需要有機制應對后端請求超時以及后端服務宕機的情況,友好的展示給用戶
前后端接口聯調">前后端接口聯調
前言-2"

以JC同事為例,他公司為前后端分離架構,前端vue全家桶;前后端人員開會協商數據接口后(主要是定義傳輸的數據和API接口),前后端並行開發;因為后台此時無法提供后端數據,所以前端需要用mock模擬假數據,管理API接口,獲取數據,到時接口聯調時連接后端服務器,訪問后端數據即可。
但是JC同事的ajax的借口寫的是與后端叔叔商量好的絕對路徑(域名+請求路徑+請求參數,跨域問題已解決),因為這是以后真正的請求路徑,所以JC同事又不像先寫本地相對路徑,后期再來修改(萬一后台叔叔開發的慢了,鬼知道有多少接口要修改呀)。於是他就迷茫了。。。
仔細看看這其實就是前后端分離中的mock數據和聯調的問題,就現在來說能解決的方式有很多種。先說mock數據,gulp,webpack, fekit (去哪兒網的一款前端自動化構建工具,據說歷史比webpack和gulp都要久遠)等等自動化構建工具都有mock數據的功能,這不是問題;再說絕對路徑的問題,其實只需要做一個host的映射就行了。
什么是前后端接口聯調
之前開發寫代碼的時候,所有的ajax數據都不是后端返回的真實數據,而是我們自己通過接口mock模擬的假數據,當前端的代碼編寫完畢,后端的接口也已經寫好之后,我們就需要把mock數據干掉,嘗試使用后端提供的數據,進行前后端的一個調試,這個過程我們就把它稱之為前后端的接口聯調。
為什么要聯調 本地的mock數據是JC同事自己寫的,肯定符合前端需求,但是后端接口首先需要測試通不通,還需要測試數據格式對不對,還有后端有沒有填寫足夠的數據,比如寫列表頁,前端想分頁,如果后端就寫了兩條測試數據,你咋整? 所以,Jack需要根據后端對接口的調整,不斷地來回切換url,這樣豈不是還在受后端的影響,還談什么毛線的前后端分離,名存實亡嘛!
如何實現前后端接口聯調">如何實現前后端接口聯調
首先,我們已經知道,目前的前后端分離的架構應用分為兩種情況:
前后端完全分離,前后端分別擁有自己的域名和服務器
前后端開發分離,但是部署時是一個域名和一台服務器

雖然架構可以采用前后端分離,但是部署有可能就不一樣了,這和項目的大小,公司的情況等等都有關系了,一個百八十人用的小系統,還得兩台服務器兩個域名,你不覺着浪費嗎?兩種不同的部署情況直接導致了前期在設計聯調方案的時候就不同了.
如果你們公司的項目在部署時是兩台服務器對應兩個域名,恭喜你,這是最nice的方案,也是聯調最舒服的方式。第二種情況,也就是開發時前后端分離,部署時是一個域名和一台服務器。知道這個之后,他就明白接下來該怎么操作了。JC同事之前在項目根目錄static文件夾下新建了一個mock文件夾,里面寫了一些json文件,當我們做聯調的時候,這些mock數據就沒用了,我們要把mock數據切換成后端提供給我們的真實的數據。
當我的朋友Jack把static文件夾下的mock數據刪除之后,在運行項目,發現報錯了,瀏覽器告訴他,你訪問的mock下面的index.json文件找不到404。
我們平時本地前端開發環境dev地址大多是 localhost:8080,而后台服務器的訪問地址就有很多種情況了,比如 后端程序猿本地IP(127.0.0.1:8889),或者外網域名,當前端與后台進行數據交互時,自然就出現跨域問題(后台服務沒做處理情況下)。axios不支持jsonp, 所以我們就要使用http-proxy-middleware中間件做代理。
現在通過在前端修改 vue-cli 的配置可解決: vue-cli中的 config/index.js 下配置 dev選項的 {proxyTable}:
<pre><code class="language-go">proxyTable: {
'/api': {
target: '127.0.0.1:8889', // 真實請求的地址
changeOrigin: true, // 是否跨域
}
}

如果你想在公司的vue項目中實現前后端聯調,不需要再使用類似於fiddler charles的抓包代理工具了,你只需要使用proxyTable這個配置項,把你需要請求的后端的服務器地址寫在target值里就OK了。
解決完跨域問題后,接下來Jack該想想怎么在一台服務器一個域名下進行聯調的問題了。比較常見的做法是前端在本地修改,本地查看,測試好了以后上傳到服務器,看看線上環境可不可以,OK的話一切都好;不行就本地接着改,然后在上傳。
聯調完之后,如何將前端打包的項目文件發給后端,這里也需要注意兩點:
<p><code>1.css,js和圖片等靜態文件</code></p>
<blockquote>
<p>這時候的靜態文件在開發階段不需要任何考慮,按照你喜歡的相對路徑或者相對於項目的根路徑的形式寫就行了,因為早晚還得交給后端。但是,需要注意:</p>
</blockquote>
<p><code>如果你采用 相對項目根路徑的書寫方式來寫你的靜態文件路徑 時,一定要先和后端商量好,將來項目部署的時候他會把你的前端整個項目放在哪里?如果不是根目錄下,你就掛了。比如:你的reset.css的路徑是 /exports/styles/common/reset.css ,后端把你前端項目放在了根目錄下的 frontEnd 文件夾下, reset.css 文件就報404了。</code></p>
<blockquote>
<p>如果后端采用的java,你需要特別注意的是, tomcat的根目錄 並不是 webapps 文件,而后端項目默認是部署在 webapps/ROOT 文件下的,所以你如果使用了相對項目根路徑的書寫方式來寫你的靜態文件路徑時,對不起又是404了。</p>
</blockquote>
<p><code>2.ajax后端數據</code></p>
<blockquote>
<p>因為現在唯一的一台服務器還是在后端程序猿那里,所以此時你還是可以寫絕對路徑(域名+請求路徑),利用hosts文件來改變域名映射實現聯調。</p>
</blockquote>
<h5 id="接口問題排錯">接口問題排錯</h5>
<p>1.查看接口日志,查看是否有任何異常信息,還有請求參數</p>
<p>2.讓前端調用接口地址改為我本地服務器接口地址,進行測試,如果本地沒問題而且遠程代碼和本地代碼一樣,就可以排除代碼同步問題</p>
<p>3.查看接口代碼,看哪個地方有可能出現異常,並且異常被捕獲沒被處理,很有運行過程出錯了,但是異常被吃掉,導致保存附件失敗並且沒有任何異常信息</p>
<p>4.登錄測試服務器,查看該服務器是否能訪問保存附件的雲端服務器地址,如果不能則測試服務器網絡問題,有可能是權限問題,被限制訪問</p>
<p>5.登錄測試服務器查看日志文件,看是否有異常信息</p>
<h4 id="接口規范">接口規范</h4>
<h5 id="后端需給出固定的路徑">后端需給出固定的路徑</h5>
<p><code>比如 /xxapi</code></p>
<h5 id="后端返回的基本數據結構">后端返回的基本數據結構</h5>
<pre><code class="language-go">data: null,
success: true,
message: "請求成功",
</code></pre>
<blockquote>
<p>默認的數據結構應該至少有這3個屬性,如果沒有數據則 <code>data</code> 為 <code>null</code> ;<code>success</code>屬性是方便前端判斷響應結果是否為成功的狀態,比如登錄頁需要響應給前端的錯誤信息有很多種,而前端首先需要知道是成功還是失敗來進行邏輯編碼;如果失敗,前端可直接將<code>message</code>顯示給用戶。</p>
</blockquote>
<h5 id="后端返回的列表頁數據結構">后端返回的列表頁數據結構</h5>
<pre><code class="language-go">data: {
list: [
{id:1, title: "1"},
{id:2, title: "2"},
...
],
pagination: {
total: 300,
current: 1,
}
},
success: true,
message: "請求成功",
</code></pre>
<blockquote>
<p><code>total</code>為記錄總數,<code>current</code>為當前第幾頁,默認顯示數前后端應商定好,比如20條,寫到各自工程的配置參數。</p>
</blockquote>
<h5 id="后端返回的詳情頁數據結構">后端返回的詳情頁數據結構</h5>
<pre><code class="language-go">data: {
title: "標題",
content: "內容",
...
},
success: true,
message: "請求成功",
</code></pre>
<h5 id="前端提交的新建--修改頁數據結構">前端提交的新建 / 修改頁數據結構</h5>
<pre><code class="language-go">title: "標題",
content: "內容",
...
</code></pre>
<h5 id="后端返回的基礎(單個)柱圖、餅圖、折線圖的圖表數據結構">后端返回的基礎(單個)柱圖、餅圖、折線圖的圖表數據結構</h5>
<pre><code class="language-go">data:[
{"x":"廣東省","y":76011802.16},
{"x":"江蘇省","y":40717628.60},
...
],
success: true,
message: "請求成功",
</code></pre>
<h5 id="后端返回的多條折線圖的圖標數據結構">后端返回的多條折線圖的圖標數據結構</h5>
<pre><code class="language-go">data:[
{"x":"廣東省","y":76011802.16, type:"阿迪達斯"},
{"x":"江蘇省","y":40717628.60, type:"耐克"},
...
],
success: true,
message: "請求成功",
</code></pre>
<h4 id="常見接口報錯及解決方案">常見接口報錯及解決方案</h4>
<p><code>在前端頁面訪問后端接口的時候,如果后端或服務器端未做一些設置,會造成頁面訪問接口失敗,在瀏覽器的控制台會顯示報錯信息。下面針對一些常見的錯誤,列出了解決方案。</code></p>
<h5 id="不通端口或不同域名產生的跨域問題">不通端口或不同域名產生的跨域問題</h5>
<p><code>Failed to load ... : No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://...' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.</code></p>
<p>出現這個錯誤是因為前端頁面跟后端接口在不同的端口或IP或域名下面,也就是跨域。關於跨域你可能需要詳細了解 <a href="https://www.cnblogs.com/you-men/p/14054348.html">跨域資源共享 CORS</a>。跨域產生的原因是瀏覽器遵循的基本安全策略 - [MDN web docs<a href="https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy">瀏覽器的同源策略]</a>。</p>
<p><code>解決方案</code></p>
<pre><code class="language-go">Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,PUT,POST,DELETE,OPTIONS
</code></pre>
<blockquote>
<p>如果后端是Java項目,一般是在開發環境服務器的nginx配置文件中添加上面幾項來統一配置,而不是在后端代碼里配置。添加完后重啟nginx,然后在瀏覽器的響應頭里應該可以看到剛才配置的幾項,說明配置成功。這里<code>Access-Control-Allow-Origin</code>設置為<code>*</code>表示允許所有的域,也可以根據具體的環境來設置具體的IP或域名。</p>
</blockquote>
<h5 id="請求頭類型的錯誤">請求頭類型的錯誤</h5>
<pre><code class="language-go">Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
</code></pre>
<blockquote>
<p>這個錯誤當前請求Content-Type的值不被支持。可能前端發送的請求頭類型有<code>application/json</code>,這個請求涉及到預檢請求,可參看 <a href="https://developer.mozilla.org/zh/docs/Web/HTTP/Access_control_CORS">HTTP訪問控制(CORS)</a>。</p>
</blockquote>
<p><code>解決方案</code></p>
<pre><code class="language-go">Access-Control-Allow-Headers: Content-Type,*
</code></pre>
<blockquote>
<p>nginx配置文件中添加這項配置,表示接收前端的<code>Content-Type</code>。</p>
</blockquote>
<h5 id="攜帶cookie設置問題">攜帶cookie設置問題</h5>
<p><code>Failed to load ... : Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. Origin 'http://...' is therefore not allowed access.</code></p>
<blockquote>
<p>出現這個錯誤是因為前端請求接口的時候在請求頭里加了<code>credentials: 'include'</code>參數攜帶cookie信息,而后端未做接收cookie的設置。</p>
</blockquote>
<p><code>解決方案</code></p>
<blockquote>
<p>nginx配置文件中添加這項配置,表示接收前端攜帶的cookie信息。只有前后端都設置,跨域攜帶cookie請求才能成功。詳細的了解可參看 [MDN web docs <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials">Access-Control-Allow-Credentials]</a></p>
</blockquote>
<h5 id="自定義響應頭解決方案">自定義響應頭解決方案</h5>
<blockquote>
<p>在獨立的前端工程中,用戶訪問到的雖然是靜態頁面,而實際上現在的前端頁面已經有了自己的路由、權限控制等等。</p>
<p>在獨立的前端工程工程中同樣會碰到一個問題:前端頁面如何比較好的獲取用戶超時狀態來退出登錄?本文介紹使用自定義響應頭字段來解決這個問題。</p>
</blockquote>
<p><code>解決方案</code></p>
<p><code>1.后端在響應頭里增加屬性, 例如</code></p>
<pre><code class="language-go">x-session-expired: 1
</code></pre>
<blockquote>
<p>后端代碼通過增加<code>x-session-expired</code>為<code>1</code>來告訴前端當前用戶超時了。然后在瀏覽器的響應里應該能看到上面這個配置。但是前端在跨域請求情況下默認只能獲取到響應頭里的<code>Cache-Control</code>、<code>Content-Language</code>、<code>Content-Type</code>、<code>Expires</code>、<code>Last-Modified</code>、<code>Pragma</code>6個基本字段,如果要獲取到剛增加的<code>x-session-expired</code>字段,需要進行下一步。</p>
</blockquote>
<p><code>2.后端增加以下配置</code></p>
<pre><code class="language-go">Access-Control-Expose-Headers: x-session-expired
</code></pre>
<blockquote>
<p>該配置的作用是指定哪些首部可以作為響應的一部分暴露給外部,這樣前端才能獲取到上面一步添加的<code>x-session-expired</code>字段及其值。</p>
</blockquote>
3.前端在fetch請求時候獲取自定義響應頭字段
<pre><code class="language-go">return fetch(url, newOptions)
.then(checkStatus)
.then(response =&gt; {
const { dispatch } = store;
const { headers } = response;
if (headers &amp;&amp; headers.has('x-session-expired')) {
// 如果有響應頭里有x-session-expired則退出
dispatch({
type: 'login/logout',
});
return;
}
return response.json();
})
.catch((e) =&gt; {
...
});
可以看到上面代碼的<code>headers.has('x-session-expired')</code>,前端通過has方法來獲取響應頭里是否有<code>x-session-expired</code>字段,來判斷是退出還是解析數據。
至此,后端設置自定義響應頭字段且前端獲取該字段的問題解決了。該方法也同樣適用於添加其他的響應頭字段,解決無權限或其他問題。
前端性能優化
內容優化
(1)減少HTTP請求數
(3)避免重定向
(4)使用Ajax緩存
(5)延遲加載組件,預加載組件
(6)減少DOM元素數量
(7)避免404
*/
服務器優化
(1)使用內容分發網絡(CDN):把網站內容分散到多個、處於不同地域位置的服務器上可以加快下載速度。
(2)GZIP壓縮
(3)設置ETag:ETags(Entity tags,實體標簽)是web服務器和瀏覽器用於判斷瀏覽器緩存中的內容和服務器中的原始內容是否匹配的一種機制。
(4)提前刷新緩沖區
(5)對Ajax請求使用GET方法
(6)避免空的圖像src
*/

css優化
1)將CSS代碼放在HTML頁面的頂部
2)避免使用CSS表達式
(3)使用&lt;link&gt;來代替@import
(4)避免使用Filters
*/

優化
(1)將JavaScript腳本放在頁面的底部。
(2)將JavaScript和CSS作為外部文件來引用:在實際應用中使用外部文件可以提高頁面速度,因為JavaScript和CSS文件都能在瀏覽器中產生緩存。
(3)縮小JavaScript和CSS
(4)刪除重復的腳本
(5)最小化DOM的訪問:使用JavaScript訪問DOM元素比較慢。
(6)開發智能的事件處理程序
(7)javascript代碼注意:謹慎使用with,避免使用eval Function函數,減少作用域鏈查找。
*/
圖像優化
(1)優化圖片大小
(2)通過CSS Sprites優化圖片
(3)不要在HTML中使用縮放圖片
(4)favicon.ico要小而且可緩存

前端安全問題

*/
1.算法加密:
(1) RSA加密
(2) MD5加密
(3) SHA256加密
*/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM