詳解從NodeJS搭建中間層再談前后端分離
之前在知道創(chuàng)宇的項(xiàng)目中有用到過(guò)nodejs作中間層,當(dāng)時(shí)還不太理解其背后真正的原因;后來(lái)在和一位學(xué)長(zhǎng)交談的過(guò)程中,也了解到螞蟻金服也在使用類似的方法,使用nodejs作為中間層去請(qǐng)求真實(shí)后臺(tái)的數(shù)據(jù);之后人到北京,也見(jiàn)到現(xiàn)在的公司也在往nodejs后端方向靠攏。隨著知識(shí)的增加,加之自己查閱資料,慢慢總結(jié)出了一些原理。
為什么要前后端分離
1、開(kāi)發(fā)效率高
前端開(kāi)發(fā)人員不用苦苦地配置各種后端環(huán)境,安裝各種莫名的插件,擺脫對(duì)后端開(kāi)發(fā)環(huán)境的依賴,一門心思寫(xiě)前端代碼就好,后端開(kāi)發(fā)人員也不用時(shí)不時(shí)的跑去幫著前端配環(huán)境。
2、職責(zé)清晰,找bug方便
以前有了bug,前端推后端,后端推前端,不知道該誰(shuí)去該,前后端分離,是誰(shuí)的問(wèn)題就該誰(shuí)去處理,處理問(wèn)題方便很多,后期代碼重構(gòu)方便,做到了高可維護(hù)性。
從做微信小程序引發(fā)的思考
最近出于愛(ài)好,寫(xiě)了個(gè)音樂(lè)播放器的微信小程序(原本想用vue寫(xiě)的,后來(lái)因?yàn)楣緲I(yè)務(wù)原因,年后可能去做微信小程序,所以就換了前端技術(shù)棧),源碼在我的GitHub上: wx-audio 。
思考:后端出于性能和別的原因,提供的接口所返回的數(shù)據(jù)格式也許不太適合前端直接使用,前端所需的排序功能、篩選功能,以及到了視圖層的頁(yè)面展現(xiàn),也許都需要對(duì)接口所提供的數(shù)據(jù)進(jìn)行二次處理。這些處理雖可以放在前端來(lái)進(jìn)行,但也許數(shù)據(jù)量一大便會(huì)浪費(fèi)瀏覽器性能。因而現(xiàn)今,增加node端便是一種良好的解決方案。
在我的微信小程序demo的server端代碼中,我通過(guò)http模塊對(duì)真實(shí)后臺(tái)(網(wǎng)易云音樂(lè)API)發(fā)起http請(qǐng)求,然后通過(guò)express模塊搭建后端服務(wù)。
發(fā)起請(qǐng)求:
// http.js var formatURL = require('./formatURL.js'); var http = require('http'); const POSThttp = function(request){ return new Promise((resolve, reject) => { let body = ''; // http模塊拿到真實(shí)后臺(tái)api的數(shù)據(jù) http.get(formatURL(request.body.musicname), function(res){ res.on('data', (data) => { body += data; }).on('end', () => { // 格式化 const { name, audio: musicUrl, page, album: { name: musicName, picUrl, }, artists: [{ name: singer, }], } = JSON.parse(body).result.songs[0]; const reply = { name, picUrl, musicUrl, page, singer, }; resolve(reply); }); }); }); }; module.exports = POSThttp;
得到數(shù)據(jù)傳回前端:
var express = require('express'); var POSThttp = require('./POSThttp.js'); var bodyParser = require('body-parser'); // 使用body-parser解析post請(qǐng)求的參數(shù),如果沒(méi)有,req.body為undefined。 var app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.post('/', (req, res) => { POSThttp(req).then((data) => { res.send(data); }).catch((err) => { res.send(err); }); }); app.listen(3000, () => { console.log('open wx-audio server successful!') });
這幾十行代碼也就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的中間層的demo,并做到了在中間層格式化參數(shù),便于前端進(jìn)行使用的過(guò)程。
為什么需要中間層?
其實(shí)這個(gè)問(wèn)題,我認(rèn)為跟面試常考的題:“為什么需要前后端分離?”是類似的,其原因可以歸納為以下幾點(diǎn):
現(xiàn)今網(wǎng)站存在問(wèn)題
之前有向一位在百度有多年工作經(jīng)驗(yàn)的老前輩交談這類問(wèn)題,我所提到的搜狐公司代碼冗余、前后端耦合的問(wèn)題,他是這么回答并且給予我這樣的建議:
其實(shí),提煉出來(lái),現(xiàn)今大公司的老項(xiàng)目(包括百度、搜狐等公司所采用的后端渲染等),或多或少都會(huì)存在這樣的一些 問(wèn)題 :
- 前端代碼越來(lái)越復(fù)雜
- 前后端依舊高度耦合
- 無(wú)法良好的支持跨終端
前輩們提出的解決方案
參考 淘寶前后端分離解決方案
- 前端代碼越來(lái)越復(fù)雜,我們希望盡可能地減少工作量,開(kāi)始使用類似MV*的分層結(jié)構(gòu),使前端后分離成為必要。
- 前端需要處理更多的工作,希望有權(quán)操控View,Router(如:SPA的嘗試)
- 各種終端設(shè)備的興起,需要我們把頁(yè)面適配到更多的地方。
開(kāi)始:我們所嘗試的CLIENT-SIDE MV* 框架,后端暴露數(shù)據(jù)接口、處理業(yè)務(wù)邏輯,前端接收數(shù)據(jù)、處理渲染邏輯。
關(guān)于MVC的定義:
MVC是一種設(shè)計(jì)模式,它將應(yīng)用劃分為3個(gè)部分:數(shù)據(jù)(模型)、展現(xiàn)層(視圖)和用戶交互(控制器)。換句話說(shuō),一個(gè)事件的發(fā)生是這樣的過(guò)程:
1. 用戶和應(yīng)用產(chǎn)生交互。
2. 控制器的事件處理器被觸發(fā)。
3. 控制器從模型中請(qǐng)求數(shù)據(jù),并將其交給視圖。
4. 視圖將數(shù)據(jù)呈現(xiàn)給用戶。
我們不用類庫(kù)或框架就可以實(shí)現(xiàn)這種MVC架構(gòu)模式。關(guān)鍵是要將MVC的每部分按照職責(zé)進(jìn)行劃分,將代碼清晰地分割為若干部分,并保持良好的解耦。這樣可以對(duì)每個(gè)部分進(jìn)行獨(dú)立開(kāi)發(fā)、測(cè)試和維護(hù)。
如:Backbone, EmberJS, KnockoutJS, AngularJS等框架。
但這樣的方式仍舊存在問(wèn)題:
各層職責(zé)重疊
- Client-side Model 是 Server-side Model 的加工
- Client-side View 跟 Server-side是 不同層次的東西
- Client-side的Controller 跟 Sever-side的Controller 各搞各的
- Client-side的Route 但是 Server-side 可能沒(méi)有
性能問(wèn)題
- 渲染,取值都在客戶端進(jìn)行,有性能的問(wèn)題
- 需要等待資源到齊才能進(jìn)行,會(huì)有短暫白屏與閃動(dòng)
- 在移動(dòng)設(shè)備低速網(wǎng)路的體驗(yàn)奇差無(wú)比
重用問(wèn)題
- 模版無(wú)法重用,造成維護(hù)上的麻煩與不一致
- 邏輯無(wú)法重用,前端的校驗(yàn)后端仍須在做一次
- 路由無(wú)法重用,前端的路由在后端未必存在
跨終端問(wèn)題
- 業(yè)務(wù)太靠前,導(dǎo)致不同端重復(fù)實(shí)現(xiàn)
- 邏輯太靠前,造成維護(hù)上的不易
渲染都在客戶端,模版無(wú)法重用,SEO實(shí)現(xiàn) 麻煩
NodeJS作為中間層的全棧開(kāi)發(fā)方案
有了NodeJS之后,前端可以更加專注于視圖層,而讓更多的數(shù)據(jù)邏輯放在Node層處理。
我們使用Node層:
- 轉(zhuǎn)發(fā)數(shù)據(jù),串接服務(wù)
- 路由設(shè)計(jì),控制邏輯
- 渲染頁(yè)面,體驗(yàn)優(yōu)化
- 中間層帶來(lái)的性能問(wèn)題,在異步ajax轉(zhuǎn)成同步渲染過(guò)程中得到平衡
- 更多的可能
其實(shí)更為重要的是,對(duì)于前端來(lái)說(shuō),NodeJS的學(xué)習(xí)成本是相當(dāng)?shù)偷模何覀儫o(wú)需學(xué)習(xí)一門新的語(yǔ)言,就能做到以前開(kāi)發(fā)幫我們做的事情,一切都顯得那么自然。
技術(shù)在不斷變化中,唯有跟上技術(shù)革新的浪潮,才能不被時(shí)代所淘汰,不管是人還是企業(yè)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
在Linux系統(tǒng)上更新Node.js到最新版本的3種方法小結(jié)
這篇文章主要介紹了在Linux系統(tǒng)上更新Node.js到最新版本的3種方法,使用NVM,使用NPM,用二進(jìn)制包更新Node.js,文中有詳解更新方法,需要的朋友可以參考下2023-09-09如何使用axios庫(kù)在Node.js中進(jìn)行代理請(qǐng)求(實(shí)踐案例)
axios是一個(gè)強(qiáng)大的基于Promise的HTTP客戶端,它在瀏覽器和Node.js環(huán)境中均可使用,本文將介紹如何充分利用axios庫(kù),在Node.js中進(jìn)行代理請(qǐng)求的最佳實(shí)踐,并通過(guò)一個(gè)實(shí)際案例來(lái)展示其應(yīng)用,感興趣的朋友一起看看吧2024-03-03Node.js開(kāi)發(fā)教程之基于OnceIO框架實(shí)現(xiàn)文件上傳和驗(yàn)證功能
這篇文章主要介紹了Node.js開(kāi)發(fā)教程之基于OnceIO框架實(shí)現(xiàn)文件上傳和驗(yàn)證的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11詳解用node.js實(shí)現(xiàn)簡(jiǎn)單的反向代理
本篇文章主要介紹了詳解用node.js實(shí)現(xiàn)簡(jiǎn)單的反向代理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06Nuxt配合Node在實(shí)際生產(chǎn)中的應(yīng)用詳解
這篇文章主要介紹了Nuxt配合Node在實(shí)際生產(chǎn)中的應(yīng)用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08Node.js實(shí)現(xiàn)注冊(cè)郵箱激活功能的方法示例
現(xiàn)在很多網(wǎng)站都需要有注冊(cè)郵箱激活的功能,本篇文章主要介紹了Node.js實(shí)現(xiàn)注冊(cè)郵箱激活功能的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03Node.js中DNS模塊學(xué)習(xí)總結(jié)
本篇文章給大家詳細(xì)介紹了Node.js中DNS模塊的相關(guān)知識(shí)點(diǎn),以及相關(guān)的實(shí)例代碼做了分享,有興趣的朋友參考下。2018-02-02