前后端分離詳解

個人博客與簡書同步:zhuzhaohua.com

概述

前段時間,與同事閑談時,談到前后端分離,接觸這個概念也有一段時間了,然而想把它描述清楚,并非易事。前后端分離不像RESTful,后者是學(xué)術(shù)成果,有篇論文擺在那里,而前后端分離是工程化實(shí)踐的產(chǎn)物,沒有人給它下過明確的定義,它不是一門技術(shù),而是一套項目實(shí)施與技術(shù)變革互相推動的方法論。這篇文章,筆者將詳細(xì)闡述這一概念的發(fā)展歷程,它解決了什么樣的問題,以及有什么缺點(diǎn)。

想要理解前后端分離,我們必須要了解web的發(fā)展史。

WEB發(fā)展史

靜態(tài)頁面的時代

在上世紀(jì)90年代,html與web概念興起,萬維網(wǎng)聯(lián)盟(W3C)誕生。這段時間可以稱之為web的洪荒時期,此時的網(wǎng)頁是靜態(tài)只讀的,不能與用戶交互,基本上只能做信息的展示。

瀏覽器一戰(zhàn)

95年開始,JavaScript、VBScript、ActionScript、JScript各種腳本語言開始興起,旨在拓展web的能力。所謂瀏覽器大戰(zhàn)是指瀏覽器廠商之間市場份額之爭,但實(shí)際上,從技術(shù)領(lǐng)域來看,這是一場腳本之戰(zhàn)。最后的輸贏其實(shí)無關(guān)緊要了,因?yàn)槟_本之爭促成ECMAScript標(biāo)準(zhǔn)的形成,也就是現(xiàn)在常提到的ES規(guī)范。規(guī)范的形成可以約束瀏覽器開發(fā)商,減少差異化,所以從這個時代開始,瀏覽器之間的差異便開始逐漸縮小,網(wǎng)頁技術(shù)也變得更加通用。

瀏覽器執(zhí)行腳本,可以給畫面以”動感“,在腳本中可以操作畫面元素,使畫面可以響應(yīng)用戶的動作,這也是動態(tài)頁面的開端。

動態(tài)頁面技術(shù)

單純靠瀏覽器中運(yùn)行的腳本,能做的事情還是很有限的,例如持久化的需要(例如用戶要在網(wǎng)頁上記錄一些內(nèi)容,并在下次訪問時仍然存在)。后臺興起的動態(tài)頁面技術(shù)滿足了逐漸膨脹的需要。代表為jsp、php、asp。這類技術(shù)可以使頁面在渲染之前,從后臺的數(shù)據(jù)庫或者其他途徑獲取所需的數(shù)據(jù)用來渲染畫面,也可以將用戶輸入的信息傳遞給后臺,實(shí)現(xiàn)數(shù)據(jù)的落地。是真正意義上的動態(tài)頁面。

這里以jsp為例,它獨(dú)自承擔(dān)了web的所有內(nèi)容,用來展示畫面的html標(biāo)簽與負(fù)責(zé)業(yè)務(wù)邏輯的java代碼都在一個文件里。在jsp容器中(如tomcat),被編譯成servlet和html。它可以看成是以java為腳本,賦予了html處理業(yè)務(wù)邏輯的能力,而java與js不同,java是運(yùn)行在后臺的,它可以與數(shù)據(jù)庫實(shí)時交互。

值得一提的是,動態(tài)頁面技術(shù)實(shí)際上是一種“動靜結(jié)合”的混合技術(shù):

動,是指后臺拼接字符串生成HTML字符流,可以根據(jù)業(yè)務(wù)邏輯不同而不同,所以稱之為動態(tài);

靜,是指不可變的純文本文件,寫什么就是什么,不能變化,所以稱之為靜態(tài);

動態(tài)頁面技術(shù)意識到了動靜結(jié)合的重要性,如果頁面全靠后臺字符串拼接,那無疑是很難維護(hù)的;而如果只使用html,則達(dá)不到動態(tài)的效果。所以,把固定的部分用靜態(tài)、可變的部分用動態(tài),動靜結(jié)合,豈不美哉。

MVC時代

動態(tài)頁面雖好,但隨著業(yè)務(wù)量的擴(kuò)大,其弊端也逐漸顯現(xiàn):代碼越來越龐大,邏輯越來越復(fù)雜,靜態(tài)的頁面部分與動態(tài)的邏輯部分彼此糾纏,緊緊的耦合在一起,變得非常難以維護(hù)。MVC模型應(yīng)運(yùn)而生,視圖層V只負(fù)責(zé)視圖,控制器C負(fù)責(zé)與業(yè)務(wù)對接,模型M是數(shù)據(jù)介質(zhì)。這依舊是動靜結(jié)合的思想,但出現(xiàn)了分工,改變了動態(tài)頁面“一鍋粥”的困境,例如在Struts中,jsp不再需要java代碼邏輯,它只需要專注于畫面的展示就可以了。在mvc時代的后期,jsp甚至被html+模板語法所取代,即便html再一次回到歷史舞臺,它卻作為mvc的一部分,被放置在后臺工程內(nèi),因?yàn)榇藭r的它只是用來渲染畫面的模板,而非畫面本身。

AJAX的出現(xiàn)

可以說沒有ajax就沒有今天的互聯(lián)網(wǎng),這一點(diǎn)也不夸張,因?yàn)槭撬嬲尞嬅鎰悠饋怼S辛薬jax,不需要刷新畫面就可以與服務(wù)器通信。這是動態(tài)畫面最直觀的需求,有了ajax,就沒必要每一次都大動干戈的刷新全畫面,只需要提供局部畫面所需的數(shù)據(jù)就可以了,這一點(diǎn)影響非常大,首先,它解放了資源:內(nèi)存、帶寬,其次,它的出現(xiàn)使后臺更專注于提供數(shù)據(jù),無需考慮表現(xiàn)層的細(xì)節(jié),而此時,RESTful的論文也發(fā)表了,二者相得益彰。

而ajax更大的貢獻(xiàn),是推動了單頁面應(yīng)用的發(fā)展。上文提到mvc時代畫面內(nèi)容的切換是通過后臺渲染整個畫面實(shí)現(xiàn)的,如今,我們有了局部刷新的能力,如果我們將這個“局部”進(jìn)一步擴(kuò)大,擴(kuò)大成“絕大部分”的畫面更新,就可以實(shí)現(xiàn)類似路由的功能,這也是單頁面應(yīng)用最基本的原理。

瀏覽器二戰(zhàn)與jQuery

這所謂的第二次戰(zhàn)爭,其實(shí)是"一戰(zhàn)"后微軟壟斷瀏覽器市場的惡果,瀏覽器一戰(zhàn)之后,IE一家獨(dú)大,開始自定標(biāo)準(zhǔn),歷史的教訓(xùn)就是壟斷都沒有好結(jié)果,火狐與谷歌瀏覽器異軍突起,很快的搶占了市場,這使得web領(lǐng)域又開始變得混亂。在這樣的背景下,開發(fā)者不得不求助于能解決兼容性問題的框架,于是社區(qū)力量開始顯現(xiàn),jQuery就是其中最優(yōu)秀的作品,時至今日,jQuery及其生態(tài)依舊是當(dāng)之無愧的霸主。
瀏覽器二戰(zhàn)最終以HTML5標(biāo)準(zhǔn)的誕生而塵埃落定,IE基本上算是廢了,Chrome,F(xiàn)irefox,Opera各領(lǐng)風(fēng)騷。

NodeJS

在瀏覽器二戰(zhàn)中,不得不提一下谷歌的Chrome,它的優(yōu)秀不僅僅表現(xiàn)在瀏覽器領(lǐng)域,它所使用的JavaScript引擎--V8,后來被運(yùn)用到后臺開發(fā)中,即NodeJS。
Node是一套獨(dú)立的、不運(yùn)行在瀏覽器中的JavaScript運(yùn)行環(huán)境,它可以使用JavaScript編寫后臺程序。對于JavaScript后臺的嘗試,歷史上有過很多次,但Node是最成功的。它的意義不僅僅是讓后臺多了一種可選的編程語言這么簡單,它打開了一扇窗戶,就是前后臺大一統(tǒng)的窗戶,讓前端那些曾被嘲諷為“每天只知道摳圖的美工”們,可以用熟悉的語言走進(jìn)后臺的世界。而且,前端人才腦洞大開,他們用node創(chuàng)造了“大前端”這個領(lǐng)域,這應(yīng)該是node作者都想象不到的事情。(關(guān)于”大前端“后文會說)

前端MVC與SPA

MVC中的C,即控制器。是表現(xiàn)層與業(yè)務(wù)層的橋梁,它負(fù)責(zé)將請求轉(zhuǎn)交給業(yè)務(wù)層,業(yè)務(wù)層處理數(shù)據(jù),并返回給控制器,控制器將數(shù)據(jù)交給模型,用來渲染畫面。前文提到,ajax的出現(xiàn),使畫面具備了直接與業(yè)務(wù)層溝通的能力,只要得到數(shù)據(jù),前端就可以使用腳本進(jìn)行畫面的渲染,而不需要后臺的渲染工作。這使得表現(xiàn)層徹底從后臺中解放出來,形成了前端的MVC,比較有代表性的框架,就是backbone了,這大概是2010年左右的事情(看似就在昨天,實(shí)際上已經(jīng)是近10年前的事情了啊)。

(【題外話】在此時 MVC這個概念已經(jīng)搖搖欲墜了,前端MVC也只是曇花一現(xiàn)。Ajax的出現(xiàn),對傳統(tǒng)的MVC架構(gòu)已經(jīng)產(chǎn)生了很大的沖擊,Ajax可以“越過”控制器,直接獲取數(shù)據(jù)并通過腳本操作視圖,有人會說:“Ajax并沒有越過控制器,而是直接向控制器發(fā)請求,這也是MVC!”。這么理解當(dāng)然也可以,但傳統(tǒng)意義上的MVC,視圖的粒度是一整個畫面,控制器對整個畫面負(fù)責(zé);而使用Ajax之后,控制器難道只對畫面上的某一小部分負(fù)責(zé)嗎?這其中的概念已經(jīng)發(fā)生了變化,MVC的危機(jī)出現(xiàn)了。那么后文會提到mvvm,是mvc的升級版,用來解決mvc所面臨的問題)。

完成前端獨(dú)自渲染的工作,還有一點(diǎn)必不可少,就是路由。在后臺MVC的時代,路由體現(xiàn)在:輸入不同的url會訪問到不同的后端控制器,以渲染不同的畫面。如果要實(shí)現(xiàn)前端渲染,就不能讓后臺“插手”,于是出現(xiàn)了HashChange以及后期html5的HistoryAPI技術(shù),通過改變url的一部分內(nèi)容不觸發(fā)后臺請求,而是觸發(fā)腳本,讓腳本去實(shí)現(xiàn)畫面的渲染,其外在表現(xiàn)與傳統(tǒng)模式?jīng)]有太大差別,這便是前端路由的實(shí)現(xiàn)。

前文提到,ajax可以直接訪問后臺,通過腳本使用ajax得到的數(shù)據(jù)渲染畫面,這讓人自然而然就想到了一件事情,就是不再需要那么多的畫面了,一張畫面就可以了,如果畫面需要改變,我們有前端的路由技術(shù),如果需要后臺提供數(shù)據(jù),就直接用ajax去取!這是單頁面應(yīng)用(SPA)。

單頁面應(yīng)用,說白了就是邏輯的前置,原本大量的后臺服務(wù)器渲染的操作,由瀏覽器來完成。這么做有非常多的優(yōu)點(diǎn),當(dāng)然也有缺點(diǎn),對此,就不在本文中闡述了,可以參見我的另一篇文章SPA與SSR

在此時,前后端分離正式開始。新的體系已經(jīng)形成:

  • UI層前端

    傳統(tǒng)意義上的前端,負(fù)責(zé)畫面的布局與樣式(前端三大件:html+css+js);

  • 中后臺前端

    把MVC搬到前臺,通過JS實(shí)現(xiàn),并逐漸演進(jìn),從MVC到MVVM,各種組件、工具、最佳實(shí)踐慢慢的被囊括進(jìn)來,有人給它起了個很大氣的名字:中后臺前端;

  • 業(yè)務(wù)層(后臺)

    原本的后臺在去掉MVC之后,只注重提供業(yè)務(wù)數(shù)據(jù)接口,一般以rest標(biāo)準(zhǔn)實(shí)現(xiàn);

  • 持久層(后臺)

    數(shù)據(jù)落地。SQL、NOSQL、文件等...這與前后端分離之前沒有差別。

那么現(xiàn)在的前端所做的,就是UI+中后臺前端所做的事情,而后臺,則是做業(yè)務(wù)層、持久層的事情,并將領(lǐng)域滲透至服務(wù)化、三高(高可用、高并發(fā)、高性能)、容器化等原本屬于運(yùn)維范疇的技術(shù)。

雙向綁定與MVVM

MVVM是MVC的升級版。核心思想就是雙向綁定,它強(qiáng)調(diào)視圖數(shù)據(jù)模型在前端的核心地位,其代表就是大名鼎鼎的前端三大框架:react、vue、angularJS。
MVVM使用ViewModel代替控制器,以雙向綁定的形式直接進(jìn)行對DOM的操作,數(shù)據(jù)模型的變化使畫面改變,畫面改變同樣會反映到數(shù)據(jù)模型上。這使得開發(fā)人員只需要關(guān)注兩件事就可以了:

  • 1 數(shù)據(jù)模型與DOM綁定;
  • 2 操作數(shù)據(jù)模型。

其實(shí)MVC模型逐漸頹勢,并不是因?yàn)镸VVM的出現(xiàn),在前文中提到,ajax破壞了MVC中控制器的定義,控制器已經(jīng)逐漸被弱化,MVVM只是順勢而為罷了。

MVVM對開發(fā)效率的提升,筆者深有感觸,曾有一基于jQuery的功能模塊,洋洋灑灑寫了6000多行,大量的操作DOM,大量的innerHtml,代碼可讀性已經(jīng)非常差了。使用vue重構(gòu)后,算上html總共才800多行,而且布局、樣式、與腳本邏輯松散,更具維護(hù)性。

大前端時代

筆者是后臺出身,之前工作的五六年時間中,因?yàn)槭褂玫募夹g(shù)比較陳舊吧,前端技術(shù)棧停留在jQuery,甚至認(rèn)為jQuery已經(jīng)非常好用了。去年,由于工作的原因開始接觸前端三大框架:react、vue、angular,接觸到了MVVM和雙向綁定,這并沒有讓我覺得有多么另人震驚。真正讓我震驚的是前端的工程化,也就是所謂的“大前端”。
如果我要使用vue打造一套前臺單頁面應(yīng)用,我需要會什么呢?答:nodeJS、webpack、eslint、babel、vue、vue-cli、vuex、vuerouter、axios、element:joy:.......筆者用整整一年的時間,才把這些東西屢清楚,然而,這只是“大前端”的冰山一角,還有混合開發(fā)在前面等我。

前端究竟是怎么“悄悄的”變成了今天這個樣子?這一切都要從nodeJS說起。

前端MVC與SPA出現(xiàn)之后,前端已經(jīng)作為一門專注的技術(shù)領(lǐng)域,開始迅速發(fā)展,但想完全脫離后臺是不可能的,畢竟作為web工程,前端最終也是要部署在服務(wù)器上。再者,在前后端分離的開發(fā)模式中,前后雙方需要明確數(shù)據(jù)接口,并自行開發(fā),那么在后臺沒有完成開發(fā)之前,前端怎么獲取數(shù)據(jù)呢?前端如果要獨(dú)立,就需要一個中間服務(wù)器,用來模擬后臺。而這個中間服務(wù)器,沒有什么比node更合適了。

上文提到,node是JS的運(yùn)行環(huán)境(官方說法是runtime,運(yùn)行時),前端人可以用熟悉的js語言搭建簡單的服務(wù)器,以支撐自己的開發(fā)。腦洞大開并且勤奮刻苦的前端人,依托強(qiáng)大的node,以及前端模塊化的方法論,實(shí)踐出了諸如webpack(模塊、打包、壓縮工具)、eslint(codestyle)、babel(標(biāo)準(zhǔn)轉(zhuǎn)碼器)等工程化工具,用node打造了出了前端自己的開發(fā)環(huán)境。在這基礎(chǔ)之上,前端領(lǐng)域真是百花齊放。如果你是做后臺的,技術(shù)選型其實(shí)不會特別苦惱,因?yàn)檫x擇性不多,java的話,那么基本上首選spring系,Python的話,基本上就是Flask和Djongo。但如果你是做前端的,選擇真的是太多太多了,當(dāng)然,前端領(lǐng)域也在總結(jié)最佳實(shí)踐,但依舊是多條線路并行發(fā)展,關(guān)于三大框架哪個更好的爭吵想必大家早有耳聞。當(dāng)然,競爭只要是良性的,就是好事,只是苦了前端人,要學(xué)的東西太多了。

什么是前后端分離?

說了這么多,該扣題了。究竟什么是前后端分離?結(jié)合上文的web發(fā)展歷程,筆者給出自己的理解:

我們將基于B/S架構(gòu)的WEB開發(fā)分為三層:表現(xiàn)層、業(yè)務(wù)層、持久層。那么前后端分離其實(shí)就是將表現(xiàn)層單獨(dú)工程化的實(shí)踐方法。

單獨(dú)工程化表現(xiàn)在以下幾個方面:

  • 開發(fā)階段:在node或其他平臺開發(fā)獨(dú)立工程,進(jìn)行調(diào)試以及打包;
  • 部署階段:以靜態(tài)頁面的形式部署在靜態(tài)文件服務(wù)器(Nginx、Apache)或tomcat等web容器
  • 運(yùn)行階段:客戶端(瀏覽器)獨(dú)自完成畫面渲染,所需的數(shù)據(jù)則通過REST與后臺交互

前端的責(zé)任范疇

分離之后,我們需要明確前端的工作范疇,先梳理一下,一個常見web應(yīng)用的工作流程:

  • 用戶打開瀏覽器,輸入網(wǎng)址,得到了一個登陸的畫面;
  • 在登錄畫面上,輸入用戶名密碼;
  • 用戶密碼提交到服務(wù)器,在數(shù)據(jù)庫驗(yàn)證,驗(yàn)證成功,服務(wù)器給這個登錄的終端頒發(fā)一個認(rèn)證并返回給它,即token;
  • 瀏覽器得到token,證明登錄成功了,此時存儲token,后續(xù)的請求都將攜帶token作為憑證;
  • 向后臺獲取當(dāng)前用戶信息;
  • 得到的用戶信息中包含權(quán)限,按照權(quán)限,控制用戶可以使用哪些功能,并渲染相應(yīng)的菜單;
  • 用戶開始使用,點(diǎn)擊某個菜單,得到該菜單的功能畫面;
  • 用戶在畫面上進(jìn)行業(yè)務(wù)操作。會發(fā)生以下事件:
    • 畫面與畫面的跳轉(zhuǎn);
    • 數(shù)據(jù)在畫面與后臺中傳遞;
    • 數(shù)據(jù)在畫面與畫面中傳遞;
  • 用戶完成操作,退出;

那么我們可以梳理出,前端究竟要做哪些事情:

  • 畫面的布局(html)
  • 畫面的樣式(css)
  • 處理邏輯(js)
  • 畫面的跳轉(zhuǎn)(hashChange、history)
  • 與用戶的交互(form)
  • 與后臺的交互(ajax、axios)
  • 畫面之間的數(shù)據(jù)交互(store)
  • 對登錄狀態(tài)、權(quán)限等的保持 (token)
  • ......

本文主要講解前后端分離,前端技術(shù)棧不在本文探討范圍內(nèi),所以以上內(nèi)容具體實(shí)現(xiàn)方法不在此處贅述。

前后端分離的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  • 進(jìn)一步的關(guān)注點(diǎn)分離

    在不分離的時代,前端沒有形成獨(dú)立的關(guān)注點(diǎn),它在很長時間都是后臺的“附屬品”。當(dāng)然,也有專門的技術(shù)領(lǐng)域去探索它,但絕對沒有今天這樣技術(shù)大發(fā)展的繁榮的景象。

  • 表現(xiàn)層解耦

    分離后,表現(xiàn)層與后臺松耦合,以數(shù)據(jù)接口對接,那么在接口不變的前提下,任何一層的更換都沒有影響,并且可以輕松的實(shí)現(xiàn)多端化,同一套后臺,不同終端采用不同的表現(xiàn)層;同時,這種解耦也會使系統(tǒng)具有更好的擴(kuò)展性。

  • 更專業(yè)更高效的團(tuán)隊

    前后端分離分工明確,對技術(shù)人員要求技術(shù)更專注,開發(fā)效率更高,技術(shù)積累更好。

缺點(diǎn):

  • 復(fù)雜度增加
    對于不太會擴(kuò)展的小項目,比如個人博客、公司網(wǎng)站等等。。。如果實(shí)施前后端分離的話,有點(diǎn)小題大做了,還是傳統(tǒng)一點(diǎn)比較好。

  • SEO

    如果是開發(fā)單頁面應(yīng)用,有一個絕對無法避免的問題,就是搜索引擎優(yōu)化,可以參見SPA與SSR

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。