浅谈express 中间件机制及实现原理


Posted in Javascript onAugust 31, 2017

简介

中间件机制可以让我们在一个给定的流程中添加一个处理步骤,从而对这个流程的输入或者输出产生影响,或者产生一些中作用、状态,或者拦截这个流程。中间件机制和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\r\nCookie:BAIDUID=E063E9B2690116090FE24E01ACDDF4AD:FG=1;BD_HOME=0',
  requestBody: 'key1=value1&key2=value2&key3=value3',
}

一个http请求分为请求行、请求头、和请求体,这三者之间通过\r\n\r\n即一个空行来分割,这里假设已经将这三者分开,requestLine(请求行)中有方法类型,请求url,http版本号,这三者通过空格来区分,headers(请求头)中的各部分通过\r\n来分割,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\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 处理的中间件

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"}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js left,right,mid函数
Jun 10 Javascript
javascript 继承实现方法
Aug 26 Javascript
判断浏览器的javascript版本的代码
Sep 03 Javascript
EXTjs4.0的store的findRecord的BUG演示代码
Jun 08 Javascript
面向对象继承实例(a如何继承b问题)(自写)
Jul 01 Javascript
Jquery绑定事件(bind和live的区别介绍)
Aug 23 Javascript
javascript查找字符串中出现最多的字符和次数的小例子
Oct 29 Javascript
JS简单的图片放大缩小的两种方法
Nov 11 Javascript
javascript中数组的sort()方法的使用介绍
Dec 18 Javascript
原生Ajax 和jQuery Ajax的区别示例分析
Dec 17 Javascript
jQuery中:last选择器用法实例
Dec 30 Javascript
ES6中的rest参数与扩展运算符详解
Jul 18 Javascript
JavaScript 通过Ajax 动态加载CheckBox复选框
Aug 31 #Javascript
BootStrap下的弹出框加载select2框架失败的解决方法
Aug 31 #Javascript
Angular2 http jsonp的实例详解
Aug 31 #Javascript
BootStrap中Table隐藏后显示问题的实现代码
Aug 31 #Javascript
Cpage.js给组件绑定事件的实现代码
Aug 31 #Javascript
基于canvas粒子系统的构建详解
Aug 31 #Javascript
Vue 组件间的样式冲突污染
Aug 31 #Javascript
You might like
PHP 事件机制(2)
2011/03/23 PHP
php 函数中使用static的说明
2012/06/01 PHP
采用thinkphp自带方法生成静态html文件详解
2014/06/13 PHP
PHP7扩展开发教程之Hello World实现方法示例
2017/08/03 PHP
JQuery 风格的HTML文本转义
2009/07/01 Javascript
Google Map Api和GOOGLE Search Api整合实现代码
2009/07/18 Javascript
运算符&&的三个不同层次
2013/04/07 Javascript
javascript页面加载完执行事件代码
2014/02/11 Javascript
Nodejs学习笔记之NET模块
2015/01/13 NodeJs
JS长整型精度问题实例分析
2015/01/13 Javascript
jQuery时间轴插件使用详解
2015/07/16 Javascript
JS密码生成与强度检测完整实例(附demo源码下载)
2016/04/06 Javascript
jQuery实现圣诞节礼物动画案例解析
2016/12/25 Javascript
react+redux的升级版todoList的实现
2017/12/18 Javascript
webpack-dev-server自动更新页面方法
2018/02/22 Javascript
在小程序中使用Echart图表的示例代码
2018/08/02 Javascript
vue2.0项目集成Cesium的实现方法
2019/07/30 Javascript
JavaScript this使用方法图解
2020/02/04 Javascript
ubuntu系统下 python链接mysql数据库的方法
2017/01/09 Python
Python正则抓取网易新闻的方法示例
2017/04/21 Python
python自动查询12306余票并发送邮箱提醒脚本
2018/05/21 Python
python之当你发现QTimer不能用时的解决方法
2019/06/21 Python
pandas.DataFrame.drop_duplicates 用法介绍
2020/07/06 Python
Blank NYC官网:夹克、牛仔裤等
2020/12/16 全球购物
函授教育个人学习的自我评价
2013/12/31 职场文书
经济管理毕业生求职信
2014/03/15 职场文书
毕业生面试求职信
2014/06/23 职场文书
民族学专业职业生涯规划范文:积跬步以至千里
2014/09/11 职场文书
“四风”问题对照检查材料思想汇报
2014/09/16 职场文书
2014年租房协议书范本
2014/10/30 职场文书
民事二审代理词
2015/05/25 职场文书
结婚喜宴祝酒词
2015/08/10 职场文书
2016年“我们的节日·清明节”活动总结
2016/04/01 职场文书
人民币使用说明书
2019/04/17 职场文书
承诺书应该怎么写?
2019/09/10 职场文书
使用jpa之动态插入与修改(重写save)
2021/11/23 Java/Android