express 中間件機制及實現原理

簡介

中間件機制能夠讓咱們在一個給定的流程中添加一個處理步驟,從而對這個流程的輸入或者輸出產生影響,或者產生一些中做用、狀態,或者攔截這個流程。中間件機制和tomcat的過濾器相似,這二者都屬於責任鏈模式的具體實現。express

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!');
});

模擬中間件機制而且模擬實現解析request的中間件

首先模擬一個requestjson

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',
}

一個http請求分爲請求行、請求頭、和請求體,這三者之間經過\r\n\r\n即一個空行來分割,這裏假設已經將這三者分開,requestLine(請求行)中有方法類型,請求urlhttp版本號,這三者經過空格來區分,headers(請求頭)中的各部分經過\r\n來分割,requestBody(請求體)中經過 & 來區分參數數組

模擬中間件機制tomcat

約定 中間件必定是一個函數而且接受 request, response, next三個參數cookie

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 = []; //存放中間件的一個數組
        this.index = 0; //當前執行的中間件在chain中的位置
    },
    use: function(handle) { //這裏默認 handle 是函數,而且這裏不作判斷
        this.chain.push(handle);
    },
    next: function() { //當調用next時執行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 處理的中間件app

function lineParser(req, res, next) {
        let items = req.requestLine.split(' ');
        req.methond = items[0];
        req.url = items[1];
        req.version = items[2];
        next(); //執行下一個中間件
    }

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(); //執行下一個中間件
}

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(); //執行下一個中間件
}

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(); //執行下一個中間件
}

測試代碼

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 = []; //存放中間件的一個數組
        this.index = 0; //當前執行的中間件在chain中的位置
    },
    use: function(handle) { //這裏默認 handle 是函數,而且這裏不作判斷
        this.chain.push(handle);
    },
    next: function() { //當調用next時執行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(); //執行下一個中間件
    }

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(); //執行下一個中間件
}

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(); //執行下一個中間件
}

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(); //執行下一個中間件
}
let app = App();
app.use(lineParser);
app.use(headersParser);
app.use(bodyParser);
app.use(middleware3);
app.next();

運行結果

將以上總體代碼運行後將打印如下信息函數

url: /iven_
methond: POST
version: HTTP/1.1
{key1: "value1", key2: "value2", key3: "value3"}
{Host: "www.baidu.com", Cookie: "BAIDUID=E063E9B2690116090FE24E01ACDDF4AD"}
相關文章
相關標籤/搜索