浅谈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 相关文章推荐
IE autocomplete internet explorer's autocomplete
Jun 30 Javascript
JS类的封装及实现代码
Dec 02 Javascript
javascript 动态修改样式和层叠样式表代码
Apr 27 Javascript
jquery实现的仿天猫侧导航tab切换效果
Aug 24 Javascript
JavaScript各类型的关系图解
Oct 16 Javascript
JavaScript使用DeviceOne开发实战(一) 配置和起步
Dec 01 Javascript
vue+iview写个弹框的示例代码
Dec 05 Javascript
vue中实现在外部调用methods的方法(推荐)
Feb 08 Javascript
JavaScript代码调试方法实例小结
Jan 05 Javascript
vue单页应用的内存泄露定位和修复问题小结
Aug 02 Javascript
Javascript 关于基本类型和引用类型的个人理解
Nov 01 Javascript
微信小程序实现树莓派(raspberry pi)小车控制
Feb 12 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
从零开始 教你如何搭建Discuz!4.1论坛
2006/07/07 PHP
PHP中foreach循环中使用引用要注意的地方
2011/01/02 PHP
PHP 中检查或过滤IP地址的实现代码
2011/11/27 PHP
php更新mysql后获取影响的行数发生异常解决方法
2013/03/28 PHP
php连接oracle数据库的方法(测试成功)
2016/05/26 PHP
thinkPHP框架实现图像裁剪、缩放、加水印的方法
2017/03/14 PHP
PHP根据树的前序遍历和中序遍历构造树并输出后序遍历的方法
2017/11/10 PHP
判断页面是关闭还是刷新的js代码
2007/01/28 Javascript
js实现数字每三位加逗号的方法
2015/02/05 Javascript
javascript实现获取字符串hash值
2015/05/10 Javascript
简单介绍JavaScript的变量和数据类型
2015/06/03 Javascript
JavaScript中的getTimezoneOffset()方法使用详解
2015/06/10 Javascript
javascript图片预加载实例分析
2015/07/16 Javascript
原生js实现旋转木马轮播图效果
2017/02/27 Javascript
详解Vue-Router源码分析路由实现原理
2019/05/15 Javascript
微信小程序移动拖拽视图-movable-view实例详解
2019/08/17 Javascript
vue实现select下拉显示隐藏功能
2019/09/30 Javascript
JS实现图片幻灯片效果代码实例
2020/05/21 Javascript
Vuex的各个模块封装的实现
2020/06/05 Javascript
python实现ip查询示例
2014/03/26 Python
Linux下编译安装MySQL-Python教程
2015/02/02 Python
Python的Bottle框架中返回静态文件和JSON对象的方法
2015/04/30 Python
Python中对元组和列表按条件进行排序的方法示例
2015/11/10 Python
一个简单的python爬虫程序 爬取豆瓣热度Top100以内的电影信息
2018/04/17 Python
使用python爬虫获取黄金价格的核心代码
2018/06/13 Python
解决Python 中英文混输格式对齐的问题
2018/07/16 Python
python 使用turtule绘制递归图形(螺旋、二叉树、谢尔宾斯基三角形)
2019/05/30 Python
Django模型验证器介绍与源码分析
2020/09/08 Python
Python实现LR1文法的完整实例代码
2020/10/25 Python
利用CSS3的flexbox实现水平垂直居中与三列等高布局
2016/09/12 HTML / CSS
介绍一下linux的文件权限
2014/07/20 面试题
物业管理公司实习生自我鉴定
2013/09/19 职场文书
国家励志奖学金获奖感言
2014/01/09 职场文书
产品售后服务承诺书
2014/05/21 职场文书
肖申克的救赎观后感
2015/06/02 职场文书
终止解除劳动合同证明书
2015/06/17 职场文书