書接上文,淺談前後端分離與實踐(一) 我們用mock伺服器搭建起來了自己的前端資料模擬服務,前後端開發過程中只需定義好介面規範,便可以相互進行各自的開發任務。聯調的時候,依照之前定義的開發規範進行資料聯調便可以了。前後端的功能更加清晰:
#後端 |
# 前端 |
##提供數據 | 接收數據,回傳資料 |
處理業務邏輯 | #處理渲染邏輯 |
Server-side MVC架構 | Client-side MV* 架構 |
#程式碼跑在伺服器上 | #程式碼跑在瀏覽器上 |
這裡分開乾淨了,分工也很明確了,看起來一切都那麼美好,but...我們也很容易發現問題的所在:
Client-side Model是Server-side Model 的加工
Client-side View 跟Server-side是不同層次的東西
Client-side的Controller 跟Sever-side的Controller 各搞各的
Client-side的Route 但是Server-side 可能沒有
##也就是說服務端和客戶端各層職責重疊,大家各搞各的,很難統一具體要做的事情。並且可能會伴隨著一些性能上的問題。最具體的表現就是我們常用的SPA應用:
- 渲染,取值都在客戶端進行,有效能的問題
##需要等待資源到齊才能進行,會有短暫白屏與閃動 在行動裝置低速網路的體驗奇差無比 渲染都在客戶端,模版無法重複使用,SEO實作麻煩 緊接著,我們程式碼量越來越大,我們需要校驗的表單也會越來越多,有時候,前端提交需要校驗一次表單。
服務端任需要進行校驗來達到資料的可靠性;前端的路由可能在服務端並不存在....等等這一系列重用性的問題。所以我們之前的重構可能需要更深層的思考。
二、開始重構
在開始重構之前,我們需要對前後端界線做一個劃分,也就是說什麼是屬於前端的範疇,什麼是屬於後端的範疇,最傳統的前後端分割可能是這樣的:
那麼問題來了:我們前後端分割的接線,就是依照工作職責來劃分的前後端;還是依照硬體環境劃分的前後端?自從了nodejs之後,我們可以從工作職能上重新定義前後端的範疇:
#可以看到,這裡的前端比之前多了個nodejs,也就是在前後端之間我們建構了一個nodejs 服務作為中間層!
為什麼我們選擇的中間層是nodejs呢?因為我們把中間層歸在了前端的範疇,那麼對前端小夥伴來說,nodejs畢竟還是個js,那麼從語法角度來說,上收起來應該沒有什麼問題。其次開發轉移成本也想對較低,不必來回切換語言的邏輯和語法:
#前端熟悉的語言,學習成本低 都是JS,可以前後端重複使用 體質適合:事件驅動、非阻塞I/O 適合IO密集型業務 執行速度也不差 好了,提前說了這麼多東西,那麼這個中間層能給我們帶來什麼了?要知道引進nodejs的開發成本也是很大的,首先就是多了一層服務,多的不說,單憑傳輸時間,就多了一層的傳輸時間啊!下面我們來研究一下什麼應用場景下的nodejs能帶給我們利大於弊的東西。
三、開始中間層之旅
引入nodejs之後,我們來重新分割前後端的功能:
這個就是中間層nodejs的主要思路,下面我們來看常見的業務場景:
1. 介面資料可靠度修復
有的時候服務端回傳給我們的資料可能不是前端想要的結構,所有用到的展現資料都是後端透過非同步介面(AJAX/JSONP)的方式提供的,前端只管展現。但是後端經常提供後端的資料邏輯,在前端還需要處理這些資料邏輯。例如我再開發一個功能的時候,有時候會碰到這樣的問題:
##服務端傳回的某個欄位為null 或服務端傳回的資料結構太深,前端需要不斷寫這樣的程式碼去判斷資料結構是否真的回傳了正確的東西,而不是個null 或undefined:
if (params.items && params.items.type && ...) {
// todo
}
對於這種情況,我們前端其實不應該去重複校驗資料的格式,這也本來不應該是瀏覽器端js需要做的事情。我們可以在中間層做介面轉發,在轉送的過程中做資料處理。而不用擔心資料回傳的問題:
router.get('/buyer/product/detail', (req, res, next) => {
httpRequest.get('/buyer/product/detail', (data) => {
// todo 处理数据
res.send(data);
})
})
2. 页面性能优化 和 SEO
有点时候我们做单页面应用,经常会碰到首屏加载性能问题,这个时候如果我们接了中间层nodejs的话,那么我们可以把首屏渲染的任务交给nodejs去做,次屏的渲染依然走之前的浏览器渲染。(前端换页,浏览器端渲染,直接输入网址,服务器渲染)服务端渲染对页面进行拼接直出html字符串,可以大幅提高首屏渲染的时间,减少用户的等待时间。这种形式应用最广的比如 Vue 的服务端渲染,里面也有相关的介绍。
其次对于单页面的SEO优化也是很好地处理方式,由于目前的ajax并不被搜索百度等搜索引擎支持,所以如果想要得到爬虫的支持,那么服务端渲染也是一种解决方法。(PS:如果觉得服务端渲染太麻烦,我这里还有一篇介绍处理SEO的另一种思路处理 Vue 单页面 Meta SEO的另一种思路可以参考)
3. 淘宝常见的需求解决方案
需求:在淘宝,单日四亿PV,页面数据来自各个不同接口,为了不影响体验,先产生页面框架后,在发起多个异步请求取数据更新页面,这些多出来的请求带来的影响不小,尤其在无线端。
解决方案:在NodeJS端使用 Bigpiper 技术,合并请求,降低负担,分批输出,不影响体验。同时可以拆分大接口为独立小接口,并发请求。串行 => 并行,大幅缩短请求时间。