基于NodeJS的前后端分離的思考與實(shí)踐(五)多終端適配
前言
近年來(lái)各站點(diǎn)基于 Web 的多終端適配進(jìn)行得如火如荼,行業(yè)間也發(fā)展出依賴(lài)各種技術(shù)的解決方案。有如基于瀏覽器原生 CSS3 Media Query 的響應(yīng)式設(shè)計(jì)、基于云端智能重排的「云適配」方案等。本文則主要探討在前后端分離基礎(chǔ)下的多終端適配方案。
關(guān)于前后端分離
關(guān)于前后端分離的方案,在《基于NodeJS的前后端分離的思考與實(shí)踐(一)》中有非常清晰的解釋。我們?cè)诜?wù)端接口和瀏覽器之間引入 NodeJS 作為渲染層,因?yàn)?NodeJS 層徹底與數(shù)據(jù)抽離,同時(shí)無(wú)需關(guān)心大量的業(yè)務(wù)邏輯,所以十分適合在這一層進(jìn)行多終端的適配工作。
UA 探測(cè)
進(jìn)行多終端適配首先要解決的是 UA 探測(cè)問(wèn)題,對(duì)于一個(gè)過(guò)來(lái)的請(qǐng)求,我們需要知道這個(gè)設(shè)備的類(lèi)型才能針對(duì)對(duì)它輸出對(duì)應(yīng)的內(nèi)容?,F(xiàn)在市面上已經(jīng)有非常成熟的兼容大量設(shè)備的 User Agent 特征庫(kù)和探測(cè)工具,這里有 Mozilla 整理的一個(gè)列表。其中,既有運(yùn)行在瀏覽器端的,也有運(yùn)行在服務(wù)端代碼層的,甚至有些工具提供了 Nginx/Apache 的模塊,負(fù)責(zé)解析每個(gè)請(qǐng)求的 UA 信息。
實(shí)際上我們推薦最后一種方式?;谇昂蠖朔蛛x的方案決定了 UA 探測(cè)只能運(yùn)行在服務(wù)器端,但如果把探測(cè)的代碼和特征庫(kù)耦合在業(yè)務(wù)代碼里并不是一個(gè)足夠友好的方案。我們把這個(gè)行為再往前挪,掛在 Nginx/Apache 上,它們負(fù)責(zé)解析每個(gè)請(qǐng)求的 UA 信息,再通過(guò)如 HTTP Header 的方式傳遞給業(yè)務(wù)代碼。
這樣做有幾點(diǎn)好處:
我們的代碼里面無(wú)需再去關(guān)注 UA 如何解析,直接從上層取出解析后的信息即可。如果在同一臺(tái)服務(wù)器上有多個(gè)應(yīng)用,則能夠共同使用同一個(gè) Nginx 解析后的 UA 信息,節(jié)省了不同應(yīng)用間的解析損耗。
來(lái)自天貓分享的基于 Nginx 的 UA 探測(cè)方案
淘寶的 Tengine Web 服務(wù)器也提供了類(lèi)似的模塊 ngx_http_user_agent_module。
值得一提的是,選用 UA 探測(cè)工具時(shí)必須要考慮特征庫(kù)的可維護(hù)性,因?yàn)槭忻嫔闲略龅脑O(shè)備類(lèi)型越來(lái)越多,每個(gè)設(shè)備都會(huì)有獨(dú)立的 User Agent,所以該特征庫(kù)必須提供良好的更新和維護(hù)策略,以適應(yīng)不斷變化的設(shè)備。
建立在 MVC 模式中的幾種適配方案
取得 UA 信息后,我們就要考慮如果根據(jù)指定的 UA 進(jìn)行終端適配了。即使在 NodeJS 層,雖然沒(méi)有了大部分的業(yè)務(wù)邏輯,但我們依然把內(nèi)部區(qū)分為 Model / Controller / View 三個(gè)模型。
我們先利用上面的圖,去解析一些已有的多終端適配方案。
建立在 Controller 上的適配方案
這種方案應(yīng)該是最簡(jiǎn)單粗暴的處理方法。通過(guò)路由(Router)將相同的 URL 統(tǒng)一傳遞到同一個(gè)控制層(Controller)??刂茖釉偻ㄟ^(guò) UA 信息將數(shù)據(jù)和模型(Model)邏輯派發(fā)到對(duì)應(yīng)的展現(xiàn)(View)進(jìn)行渲染,渲染層則按預(yù)先的約定提供了適配幾個(gè)終端的模板。
這種方案的好處是,保持了數(shù)據(jù)和控制層的統(tǒng)一性,業(yè)務(wù)邏輯只需處理一次遍可以應(yīng)用在所有終端上。但這種場(chǎng)景只適合如展示型頁(yè)面等低交互型的應(yīng)用,一旦業(yè)務(wù)比較復(fù)雜,各個(gè)終端的 Controller 可能有各自的處理邏輯,如果還是共用一個(gè) Controller ,會(huì)導(dǎo)致 Controller 非常的臃腫而且難以維護(hù),這無(wú)疑是一個(gè)錯(cuò)誤的選擇。
建立在 Router 上的適配方案
為了解決上面遇到的問(wèn)題,我們可以在 Router 上就將設(shè)備區(qū)分,針對(duì)不同的終端分發(fā)到不同的 Controller 上:
這也是最常見(jiàn)的方案之一,大多表現(xiàn)在針對(duì)不同終端使用各自獨(dú)立的一套應(yīng)用。如 PC 淘寶首頁(yè)和 WAP 版的淘寶首頁(yè),不同設(shè)備訪(fǎng)問(wèn) www.taobao.com ,服務(wù)器會(huì)通過(guò) Router 的控制,重定向到 WAP 版的淘寶首頁(yè)或者 PC 版的淘寶首頁(yè),它們各自是完全獨(dú)立的兩套應(yīng)用。
但這種方案無(wú)疑帶來(lái)了數(shù)據(jù)和部分邏輯無(wú)法共用的問(wèn)題,各種終端之間無(wú)法分享同一份數(shù)據(jù)和業(yè)務(wù)邏輯,產(chǎn)生大量重復(fù)性工作,效率低下。
為了緩解這個(gè)問(wèn)題,有人提出了優(yōu)化后的方案:依然是在同一套應(yīng)用里面,各個(gè)數(shù)據(jù)來(lái)源抽象成各個(gè) Model,提供給不同終端的 Controller 組合使用:
這個(gè)方案解決了前面數(shù)據(jù)無(wú)法共用的問(wèn)題。在 Controller 上各個(gè)終端還是相互獨(dú)立,但能共同使用同一批數(shù)據(jù)源,至少在數(shù)據(jù)上無(wú)需再針對(duì)終端類(lèi)型開(kāi)發(fā)獨(dú)立的接口了。
以上兩種基于 Router 的方案,由于 Controller 的獨(dú)立,各個(gè)終端可以為自己的頁(yè)面實(shí)現(xiàn)不同的交互邏輯,保證了各終端自身足夠的靈活度,這也是為什么大部分應(yīng)用采用這種方案的主要原因。
建立在 View 層的適配方案
這是淘寶下單頁(yè)面使用的方案,不過(guò)區(qū)別是下單頁(yè)將整體的渲染層放在了瀏覽器端,而不是 NodeJS 層。不過(guò)無(wú)論是瀏覽器還是 NodeJS,整體設(shè)計(jì)思路還是一致的:
在這個(gè)方案里面,Router、Controller 和 Model 都無(wú)需關(guān)注設(shè)備信息,終端類(lèi)型的判斷完全交給展現(xiàn)層來(lái)處理。圖中主要的模塊是「View Factory」,Model 和 Controller 將數(shù)據(jù)和渲染邏輯傳遞過(guò)來(lái)之后,通過(guò) View Factory 根據(jù)設(shè)備信息和其它狀態(tài)(不僅僅是 UA 信息、也可以是網(wǎng)絡(luò)環(huán)境、用戶(hù)地區(qū)等等)從一堆預(yù)設(shè)好的組件(View Component)中抓取特定的組件,再組合成最終的頁(yè)面。
這種方案有幾個(gè)優(yōu)勢(shì):
上層無(wú)需關(guān)注設(shè)備信息(UA),多終端的視頻還是交由和最終展現(xiàn)最大關(guān)系的 View 層來(lái)處理;不僅僅是多終端適配,除了 UA 信息,各個(gè) View Component 還可以根據(jù)用戶(hù)狀態(tài)決定自身輸出何種模版,如低網(wǎng)速下默認(rèn)隱藏圖片、指定地區(qū)輸出活動(dòng) Banner。每個(gè) View Component 的不同模版間可以自行決定是否使用同一份數(shù)據(jù)、業(yè)務(wù)邏輯,提供十分靈活的實(shí)現(xiàn)方式。
但明顯的是,這個(gè)方案也是最復(fù)雜的,尤其是要考慮一些富交互的應(yīng)用場(chǎng)景時(shí),Router 和 Controller 也許無(wú)法保持這么純粹。特別對(duì)于一些整體性比較強(qiáng)的業(yè)務(wù),本身無(wú)法被拆分成組件,這種方案也許并不適用;而且對(duì)于一些簡(jiǎn)單的業(yè)務(wù),使用這種架構(gòu)可能不是最佳的選擇。
總結(jié)
以上幾種方案,都各自體現(xiàn)在 MVC 模型中的一個(gè)或多個(gè)部分,在業(yè)務(wù)上如果一個(gè)方案不滿(mǎn)足需求,更可以采取多個(gè)方案同時(shí)采用的方式?;蚴强梢岳斫鉃椋瑯I(yè)務(wù)上的復(fù)雜度和交互屬性決定了該產(chǎn)品更適合采用哪種多終端適配方案。
對(duì)比基于瀏覽器的響應(yīng)式設(shè)計(jì)方案,因?yàn)榻^大部分終端探測(cè)和渲染邏輯遷移到了服務(wù)端,所以在 NodeJS 層進(jìn)行適配無(wú)疑帶來(lái)了更好的性能和用戶(hù)體驗(yàn);另外,相對(duì)于一些所謂的「云適配」方案帶來(lái)的轉(zhuǎn)換質(zhì)量問(wèn)題,在基于前后端分離的「定制式」方案中也不會(huì)存在。前后端分離的適配方案在這些方面有著天然優(yōu)勢(shì)。
最后,為了適應(yīng)更靈活的強(qiáng)大的適配需求,基于前后端分離的適配方案將會(huì)面臨更多挑戰(zhàn)!
- Node.js的Koa框架上手及MySQL操作指南
- 基于NodeJS的前后端分離的思考與實(shí)踐(三)輕量級(jí)的接口配置建模框架
- 基于NodeJS的前后端分離的思考與實(shí)踐(六)Nginx + Node.js + Java 的軟件棧部署實(shí)踐
- 基于NodeJS的前后端分離的思考與實(shí)踐(四)安全問(wèn)題解決方案
- 基于NodeJS的前后端分離的思考與實(shí)踐(二)模版探索
- 基于NodeJS的前后端分離的思考與實(shí)踐(一)全棧式開(kāi)發(fā)
- 基于 Node.js 實(shí)現(xiàn)前后端分離
- 利用Node.js+Koa框架實(shí)現(xiàn)前后端交互的方法
相關(guān)文章
nodejs實(shí)現(xiàn)百度輿情接口應(yīng)用示例
這篇文章主要介紹了nodejs實(shí)現(xiàn)百度輿情接口應(yīng)用,結(jié)合實(shí)例形式分析了node.js調(diào)用百度輿情接口的具體使用技巧,需要的朋友可以參考下2020-02-02NodeJs的優(yōu)勢(shì)和適合開(kāi)發(fā)的程序
做頁(yè)游或webqq這樣的應(yīng)用nodejs有優(yōu)勢(shì),但如果做微博、豆瓣、facebook這樣的社交網(wǎng)絡(luò),nodejs還有優(yōu)勢(shì)嗎?另外不知道大家是什么原因選擇的nodejs?是因?yàn)閼?yīng)用需求還是對(duì)javascript這門(mén)語(yǔ)言的喜歡?2016-08-08Node.js DES加密的簡(jiǎn)單實(shí)現(xiàn)
下面小編就為大家?guī)?lái)一篇Node.js DES加密的簡(jiǎn)單實(shí)現(xiàn)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07express搭建的nodejs項(xiàng)目使用webpack進(jìn)行壓縮打包
對(duì)于打包這個(gè)問(wèn)題它并不是難點(diǎn),但是對(duì)于我們這種初學(xué)者來(lái)說(shuō),根本就不知道應(yīng)該怎么做,下面這篇文章主要給大家介紹了關(guān)于express搭建的nodejs項(xiàng)目使用webpack進(jìn)行壓縮打包的相關(guān)資料,需要的朋友可以參考下2022-12-12node.js中http模塊和url模塊的簡(jiǎn)單介紹
這篇文章主要給大家簡(jiǎn)單介紹了關(guān)于node.js中的http模塊和url模塊,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用node.js具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10Nodejs + Websocket 指定發(fā)送及群聊的實(shí)現(xiàn)
這篇文章主要介紹了Nodejs + Websocket 指定發(fā)送及群聊的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01Node在Controller層進(jìn)行數(shù)據(jù)校驗(yàn)的過(guò)程詳解
這篇文章主要給大家介紹了關(guān)于Node在Controller層進(jìn)行數(shù)據(jù)校驗(yàn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08NodeJS鏈接MySql數(shù)據(jù)庫(kù)的操作方法
下面小編就為大家?guī)?lái)一篇NodeJS鏈接MySql數(shù)據(jù)庫(kù)的操現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06