资讯专栏INFORMATION COLUMN

express 中间件机制及实现原理

everfight / 592人阅读

摘要:简介中间件机制可以让我们在一个给定的流程中添加一个处理步骤,从而对这个流程的输入或者输出产生影响,或者产生一些中作用状态,或者拦截这个流程。中间件机制和的过滤器类似,这两者都属于责任链模式的具体实现。

简介

中间件机制可以让我们在一个给定的流程中添加一个处理步骤,从而对这个流程的输入或者输出产生影响,或者产生一些中作用、状态,或者拦截这个流程。中间件机制和tomcat的过滤器类似,这两者都属于责任链模式的具体实现。

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的中间件

首先模拟一个request

request = { //模拟的request
    requestLine: "POST /iven_ HTTP/1.1",
    headers: "Host:www.baidu.com
Cookie:BAIDUID=E063E9B2690116090FE24E01ACDDF4AD:FG=1;BD_HOME=0",
    requestBody: "key1=value1&key2=value2&key3=value3",
}

一个http请求分为请求行、请求头、和请求体,这三者之间通过 即一个空行来分割,这里假设已经将这三者分开,requestLine(请求行)中有方法类型,请求urlhttp版本号,这三者通过空格来区分,headers(请求头)中的各部分通过 来分割,requestBody(请求体)中通过 & 来区分参数

模拟中间件机制

约定 中间件一定是一个函数并且接受 request, response, 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
Cookie: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 处理的中间件

 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("
");
    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
Cookie: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("
");
    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"}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84966.html

相关文章

  • Express与Koa间件机制分析(一)

    摘要:目前使用人数众多。通过利用函数,帮你丢弃回调函数,并有力地增强错误处理。这个系列的博客主要讲解和的中间件机制,本篇将主要讲解的中间件机制。其中间件机制的核心为内部方法的实现。 提到 Node.js 开发,不得不提目前炙手可热的2大框架 Express 和 Koa。 Express 是一个保持最小规模的灵活的 Node.js Web 应用程序开发框架,为 Web 和移动应用程序提供一组...

    zilu 评论0 收藏0
  • 详谈HTTP的缓存机制原理

    摘要:对于的缓存机制来说,策略体现在的头部信息的字段上,而这些策略根据是否需要重新向服务器端发起请求可以分为强缓存和协商缓存两大类。接下来就是要介绍,两类缓存相关相关字段的控制实现了。 概述 缓存的重要性不言而喻,通过网络请求资源缓慢并且降低了客户端的用户体验,增添了服务端的负担。很多短期之内不会经常发生变化的资源文件没必要每次访问都想服务端进行数据请求,而缓存策略的使用就是为了改善客户端的...

    Jason_Geng 评论0 收藏0
  • 全栈最后一公里 - Node.js 项目的线上服务器部署与发布

    摘要:没有耐心阅读的同学,可以直接前往学习全栈最后一公里。我下面会罗列一些,我自己录制过的一些项目,或者其他的我觉得可以按照这个路线继续深入学习的项目资源。 showImg(https://segmentfault.com/img/bVMlke?w=833&h=410); 本文技术软文,阅读需谨慎,长约 7000 字,通读需 5 分钟 大家好,我是 Scott,本文通过提供给大家学习的方法,...

    Nosee 评论0 收藏0
  • 前端面试题大集合:来自真实大厂的532道面试题(只有题,没有答案)

    答案自己谷歌或百度找。 一、来源背景 面试题是来自微博@牛客网发布的真实大厂前端面经题目,我一直在收集题目长期一个一个的记录下来的,可能会有重复,但基本前端的面试大纲和需要掌握的知识都在其中了,面试题仅做学习参考,学习者阅后也要用心钻研其中的原理,重要知识需要系统学习、透彻学习,形成自己的知识链。 二、532道前端真实大厂面试题 express和koa的对比,两者中间件的原理,koa捕获异常多种情...

    Kerr1Gan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<