淺談express 中間件機(jī)制及實(shí)現(xiàn)原理
簡介
中間件機(jī)制可以讓我們在一個(gè)給定的流程中添加一個(gè)處理步驟,從而對這個(gè)流程的輸入或者輸出產(chǎn)生影響,或者產(chǎn)生一些中作用、狀態(tài),或者攔截這個(gè)流程。中間件機(jī)制和tomcat的過濾器類似,這兩者都屬于責(zé)任鏈模式的具體實(shí)現(xiàn)。
express 中間件使用案例
let express = require('express') let app = express() //解析request 的body app.use(bodyParser.json()) //解析 cookie app.use(cookieParser()) //攔截 app.get('/hello', function (req, res) { res.send('Hello World!'); });
模擬中間件機(jī)制并且模擬實(shí)現(xiàn)解析request的中間件
首先模擬一個(gè)request
request = { //模擬的request requestLine: 'POST /iven_ HTTP/1.1', headers: 'Host:www.baidu.com\r\nCookie:BAIDUID=E063E9B2690116090FE24E01ACDDF4AD:FG=1;BD_HOME=0', requestBody: 'key1=value1&key2=value2&key3=value3', }
一個(gè)http
請求分為請求行、請求頭、和請求體,這三者之間通過\r\n\r\n
即一個(gè)空行來分割,這里假設(shè)已經(jīng)將這三者分開,requestLine
(請求行)中有方法類型,請求url,http版本號,這三者通過空格來區(qū)分,headers
(請求頭)中的各部分通過\r\n
來分割,requestBody
(請求體)中通過 & 來區(qū)分參數(shù)
模擬中間件機(jī)制
約定 中間件一定是一個(gè)函數(shù)并且接受 request, response, next三個(gè)參數(shù)
function App() { if (!(this instanceof App)) return new App(); this.init(); } App.prototype = { constructor: App, init: function() { this.request = { //模擬的request requestLine: 'POST /iven_ HTTP/1.1', headers: 'Host:www.baidu.com\r\nCookie:BAIDUID=E063E9B2690116090FE24E01ACDDF4AD:FG=1;BD_HOME=0', requestBody: 'key1=value1&key2=value2&key3=value3', }; this.response = {}; //模擬的response this.chain = []; //存放中間件的一個(gè)數(shù)組 this.index = 0; //當(dāng)前執(zhí)行的中間件在chain中的位置 }, use: function(handle) { //這里默認(rèn) handle 是函數(shù),并且這里不做判斷 this.chain.push(handle); }, next: function() { //當(dāng)調(diào)用next時(shí)執(zhí)行index所指向的中間件 if (this.index >= this.chain.length) return; let middleware = this.chain[this.index]; this.index++; middleware(this.request, this.response, this.next.bind(this)); }, }
對 request 處理的中間件
function lineParser(req, res, next) { let items = req.requestLine.split(' '); req.methond = items[0]; req.url = items[1]; req.version = items[2]; next(); //執(zhí)行下一個(gè)中間件 } function headersParser(req, res, next) { let items = req.headers.split('\r\n'); let header = {} for(let i in items) { let item = items[i].split(':'); let key = item[0]; let value = item[1]; header[key] = value; } req.header = header; next(); //執(zhí)行下一個(gè)中間件 } function bodyParser(req, res, next) { let bodyStr = req.requestBody; let body = {}; let items = bodyStr.split('&'); for(let i in items) { let item = items[i].split('='); let key = item[0]; let value = item[1]; body[key] = value; } req.body = body; next(); //執(zhí)行下一個(gè)中間件 } function middleware3(req, res, next) { console.log('url: '+req.url); console.log('methond: '+req.methond); console.log('version: '+req.version); console.log(req.body); console.log(req.header); next(); //執(zhí)行下一個(gè)中間件 }
測試代碼
let app = App(); app.use(lineParser); app.use(headersParser); app.use(bodyParser); app.use(middleware3); app.next();
整體代碼
function App() { if (!(this instanceof App)) return new App(); this.init(); } App.prototype = { constructor: App, init: function() { this.request = { //模擬的request requestLine: 'POST /iven_ HTTP/1.1', headers: 'Host:www.baidu.com\r\nCookie:BAIDUID=E063E9B2690116090FE24E01ACDDF4AD:FG=1;BD_HOME=0', requestBody: 'key1=value1&key2=value2&key3=value3', }; this.response = {}; //模擬的response this.chain = []; //存放中間件的一個(gè)數(shù)組 this.index = 0; //當(dāng)前執(zhí)行的中間件在chain中的位置 }, use: function(handle) { //這里默認(rèn) handle 是函數(shù),并且這里不做判斷 this.chain.push(handle); }, next: function() { //當(dāng)調(diào)用next時(shí)執(zhí)行index所指向的中間件 if (this.index >= this.chain.length) return; let middleware = this.chain[this.index]; this.index++; middleware(this.request, this.response, this.next.bind(this)); }, } function lineParser(req, res, next) { let items = req.requestLine.split(' '); req.methond = items[0]; req.url = items[1]; req.version = items[2]; next(); //執(zhí)行下一個(gè)中間件 } function headersParser(req, res, next) { let items = req.headers.split('\r\n'); let header = {} for(let i in items) { let item = items[i].split(':'); let key = item[0]; let value = item[1]; header[key] = value; } req.header = header; next(); //執(zhí)行下一個(gè)中間件 } function bodyParser(req, res, next) { let bodyStr = req.requestBody; let body = {}; let items = bodyStr.split('&'); for(let i in items) { let item = items[i].split('='); let key = item[0]; let value = item[1]; body[key] = value; } req.body = body; next(); //執(zhí)行下一個(gè)中間件 } function middleware3(req, res, next) { console.log('url: '+req.url); console.log('methond: '+req.methond); console.log('version: '+req.version); console.log(req.body); console.log(req.header); next(); //執(zhí)行下一個(gè)中間件 } let app = App(); app.use(lineParser); app.use(headersParser); app.use(bodyParser); app.use(middleware3); app.next();
運(yùn)行結(jié)果
將以上整體代碼運(yùn)行后將打印以下信息
url: /iven_ methond: POST version: HTTP/1.1 {key1: "value1", key2: "value2", key3: "value3"} {Host: "www.baidu.com", Cookie: "BAIDUID=E063E9B2690116090FE24E01ACDDF4AD"}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
express框架中使用jwt實(shí)現(xiàn)驗(yàn)證的方法
這篇文章主要給大家介紹了關(guān)于express框架中使用jwt實(shí)現(xiàn)驗(yàn)證的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用express具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Nodejs搭建多進(jìn)程Web服務(wù)器實(shí)現(xiàn)過程
這篇文章主要為大家介紹了Nodejs搭建多進(jìn)程Web服務(wù)器實(shí)現(xiàn)過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10詳解NodeJs支付寶移動(dòng)支付簽名及驗(yàn)簽
本文主要介紹了NodeJs支付寶移動(dòng)支付簽名及驗(yàn)簽的方法,具有一定的參考價(jià)值,下面跟著小編一起來看下吧2017-01-01Node.js中DNS模塊學(xué)習(xí)總結(jié)
本篇文章給大家詳細(xì)介紹了Node.js中DNS模塊的相關(guān)知識點(diǎn),以及相關(guān)的實(shí)例代碼做了分享,有興趣的朋友參考下。2018-02-02通過nodejs 服務(wù)器讀取HTML文件渲染到頁面的方法
今天小編就為大家分享一篇通過nodejs 服務(wù)器讀取HTML文件渲染到頁面的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05npm安裝yarn后找不到y(tǒng)arn報(bào)錯(cuò)的解決過程
這篇文章主要給大家介紹了關(guān)于npm安裝yarn后找不到y(tǒng)arn報(bào)錯(cuò)的解決過程,文中通過圖文介紹的非常詳細(xì),對遇到同樣問題的同學(xué)具有一定的參考性,需要的朋友可以參考下2023-04-04基于 Node 實(shí)現(xiàn)簡易 serve靜態(tài)資源服務(wù)器的示例詳解
靜態(tài)資源服務(wù)器(HTTP 服務(wù)器)可以將靜態(tài)文件(如 js、css、圖片)等通過 HTTP 協(xié)議展現(xiàn)給客戶端。本文介紹如何基于 Node 實(shí)現(xiàn)一個(gè)簡易的靜態(tài)資源服務(wù)器,感興趣的朋友一起看看吧2022-06-06