浅谈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 相关文章推荐
弹出广告特效(一个IP只弹出一次)的代码
Jul 27 Javascript
当鼠标移动到图片上时跟随鼠标显示放大的图片效果
Jun 06 Javascript
open 动态修改img的onclick事件示例代码
Nov 13 Javascript
jquery.cookie用法详细解析
Dec 18 Javascript
8个实用的jQuery技巧
Mar 04 Javascript
js实现同一页面可多次调用的图片幻灯切换效果
Feb 28 Javascript
jQuery防止重复绑定事件的解决方法
May 14 Javascript
详解JavaScript节流函数中的Throttle
Jul 16 Javascript
JS 调用微信扫一扫功能
Dec 22 Javascript
jQuery实现拖动效果的实例代码
Jun 25 jQuery
浅析node应用的timing-attack安全漏洞
Feb 28 Javascript
ES6中的Javascript解构的实现
Oct 30 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设计模式中单例模式的应用分析
2013/05/15 PHP
Thinkphp中的curd应用实用要点
2015/01/04 PHP
PHP magento后台无法登录问题解决方法
2016/11/24 PHP
php基于session锁防止阻塞请求的方法分析
2017/08/07 PHP
关于laravel框架中的常用目录路径函数
2019/10/23 PHP
关于Ext中form移除textfield方法:hide(),setVisible(false),remove()
2010/12/02 Javascript
使用原生js封装webapp滑动效果(惯性滑动、滑动回弹)
2014/05/06 Javascript
JavaScript AJAX之惰性载入函数
2014/08/27 Javascript
基于JS实现textarea中获取动态剩余字数的方法
2016/05/25 Javascript
利用JS实现文字的聚合动画效果
2017/01/22 Javascript
vue.js 实现点击展开收起动画效果
2018/07/07 Javascript
js实现可爱的气泡特效
2020/09/05 Javascript
Nodejs在局域网配置https访问的实现方法
2020/10/17 NodeJs
JS中锚点链接点击平滑滚动并自由调整到顶部位置
2021/02/06 Javascript
Python性能提升之延迟初始化
2016/12/04 Python
对变量赋值的理解--Pyton中让两个值互换的实现方法
2017/11/29 Python
Python2中文处理纪要的实现方法
2018/03/10 Python
Python连接Oracle之环境配置、实例代码及报错解决方法详解
2020/02/11 Python
python3注册全局热键的实现
2020/03/22 Python
PIL.Image.open和cv2.imread的比较与相互转换的方法
2020/06/03 Python
浅谈keras中的batch_dot,dot方法和TensorFlow的matmul
2020/06/18 Python
matplotlib 使用 plt.savefig() 输出图片去除旁边的空白区域
2021/01/05 Python
解决pycharm 格式报错tabs和space不一致问题
2021/02/26 Python
UNDONE手表官网:世界领先的定制手表品牌
2018/11/13 全球购物
印尼极简主义和实惠的在线家具店:Fabelio
2019/03/27 全球购物
医学生实习自我鉴定
2013/09/27 职场文书
新闻记者个人求职的自我评价
2013/11/28 职场文书
自我评价怎么写好呢?
2013/12/05 职场文书
产品销售员岗位职责
2013/12/18 职场文书
医院院务公开实施方案
2014/05/03 职场文书
家长会后的感想
2015/08/11 职场文书
素质教育培训心得体会
2016/01/19 职场文书
postgresql 删除重复数据案例详解
2021/08/02 PostgreSQL
继承Win10缺点!教你关闭Win11烦人的网络搜索
2021/11/23 数码科技
浅谈redis的过期时间设置和过期删除机制
2022/03/18 MySQL
MYSQL如何查看操作日志详解
2022/05/30 MySQL