浅谈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 相关文章推荐
基于jQuery的前端数据通用验证库
Aug 08 Javascript
js 判断js函数、变量是否存在的简单示例代码
Mar 04 Javascript
jQuery的cookie插件实现保存用户登陆信息
Apr 15 Javascript
常用jQuery选择器总结
Jul 11 Javascript
java、javascript实现附件下载示例
Aug 14 Javascript
javascript经典特效分享 手风琴、轮播图、图片滑动
Sep 14 Javascript
详谈js中数组(array)和对象(object)的区别
Feb 27 Javascript
详述 Sublime Text 打开 GBK 格式中文乱码的解决方法
Oct 26 Javascript
LayUI表格批量删除方法
Aug 15 Javascript
微信小程序实现Session功能及无法获取session问题的解决方法
May 07 Javascript
React组件对子组件children进行加强的方法
Jun 23 Javascript
VSCode搭建React Native环境
May 07 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&mysql 日期操作小记
2012/02/27 PHP
php图片加水印原理(超简单的实例代码)
2013/01/18 PHP
php使用NumberFormatter格式化货币的方法
2015/03/21 PHP
PHP利用二叉堆实现TopK-算法的方法详解
2017/04/24 PHP
JavaScript中的其他对象
2008/01/16 Javascript
JQuery.ajax传递中文参数的解决方法 推荐
2011/03/28 Javascript
jquery取消选择select下拉框示例代码
2014/02/22 Javascript
JavaScript的ExtJS框架中数面板TreePanel的使用实例解析
2016/05/21 Javascript
jQuery轻松实现无缝轮播效果
2017/03/22 jQuery
解决JS内存泄露之js对象和dom对象互相引用问题
2017/06/25 Javascript
WdatePicker.js时间日期插件的使用方法
2017/07/26 Javascript
nodejs使用express获取get和post传值及session验证的方法
2017/11/09 NodeJs
Vue实现固定定位图标滑动隐藏效果
2019/05/30 Javascript
javascript实现弹幕墙效果
2019/11/28 Javascript
微信小程序vant弹窗组件的实现方式
2020/02/21 Javascript
JS实现进度条动态加载特效
2020/03/25 Javascript
vue实现lodop打印功能的示例
2020/11/11 Javascript
python实现线程池的方法
2015/06/30 Python
Python绘制七段数码管实例代码
2017/12/20 Python
基于python实现名片管理系统
2018/11/30 Python
利用python在excel里面直接使用sql函数的方法
2019/02/08 Python
python实现一行输入多个值和一行输出多个值的例子
2019/07/16 Python
Python Dict找出value大于某值或key大于某值的所有项方式
2020/06/05 Python
python 实现压缩和解压缩的示例
2020/09/22 Python
Pycharm配置lua编译环境过程图解
2020/11/28 Python
使用bandit对目标python代码进行安全函数扫描的案例分析
2021/01/27 Python
一款纯css3制作的2015年元旦雪人动画特效教程
2014/12/29 HTML / CSS
Canvas实现放大镜效果完整案例分析(附代码)
2020/11/26 HTML / CSS
Merrell美国官网:美国登山运动鞋品牌
2018/02/07 全球购物
英国健身超市:Fitness Superstore
2019/06/17 全球购物
证券期货行业个人的自我评价
2013/12/26 职场文书
服务口号大全
2014/06/11 职场文书
司机岗位职责范本
2015/04/10 职场文书
停发工资证明范本
2015/06/12 职场文书
2016年公务员六五普法心得体会
2016/01/21 职场文书
宪法宣传标语100条
2019/10/15 职场文书