浅谈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 相关文章推荐
利用javascript查看html源文件
Nov 08 Javascript
JavaScript中instanceof运算符的用法总结
Nov 19 Javascript
javascript生成json数据简单示例分享
Feb 14 Javascript
使用变量动态设置js的属性名
Oct 19 Javascript
javascript简单实现跟随滚动条漂浮的返回顶部按钮效果
Aug 19 Javascript
利用node.js搭建简单web服务器的方法教程
Feb 20 Javascript
jquery实现限制textarea输入字数的方法
Sep 06 jQuery
vue axios基于常见业务场景的二次封装的实现
Sep 21 Javascript
对angularJs中ng-style动态改变样式的实例讲解
Sep 30 Javascript
详解puppeteer使用代理
Dec 27 Javascript
Vue动态加载图片在跨域时无法显示的问题及解决方法
Mar 10 Javascript
三种方式清除vue路由跳转router-link的历史记录
Apr 10 Vue.js
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
推荐文章系统(一)
2006/10/09 PHP
洪恩在线成语词典小偷程序php版
2012/04/20 PHP
论坛里点击别人帖子下面的回复,回复标题变成“回复 24# 的帖子”
2009/06/14 Javascript
Three.js学习之网格
2016/08/10 Javascript
JavaScript 总结几个提高性能知识点(推荐)
2017/02/20 Javascript
JavaScript用二分法查找数据的实例代码
2017/06/17 Javascript
浅析从vue源码看观察者模式
2018/01/29 Javascript
js与jQuery实现获取table中的数据并拼成json字符串操作示例
2018/07/12 jQuery
JS中使用react-tooltip插件实现鼠标悬浮显示框
2019/05/15 Javascript
Vue.js+cube-ui(Scroll组件)实现类似头条效果的横向滚动导航条
2019/06/24 Javascript
vue滚动插件better-scroll使用详解
2019/10/18 Javascript
node爬取新型冠状病毒的疫情实时动态
2020/02/06 Javascript
JavaScript实现移动端拖动元素
2020/11/24 Javascript
[56:46]Liquid vs IG 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
python 调用HBase的简单实例
2016/12/18 Python
Python自然语言处理之词干,词形与最大匹配算法代码详解
2017/11/16 Python
Python3中正则模块re.compile、re.match及re.search函数用法详解
2018/06/11 Python
spark dataframe 将一列展开,把该列所有值都变成新列的方法
2019/01/29 Python
pytorch+lstm实现的pos示例
2020/01/14 Python
Python安装tar.gz格式文件方法详解
2020/01/19 Python
Python PyQt5运行程序把输出信息展示到GUI图形界面上
2020/04/27 Python
Python 如何查找特定类型文件
2020/08/17 Python
python安装第三方库如xlrd的方法
2020/10/31 Python
Django模板报TemplateDoesNotExist异常(亲测可行)
2020/12/18 Python
Python约瑟夫生者死者小游戏实例讲解
2021/01/04 Python
美国棒球装备和用品商店:Baseball Savings
2018/06/09 全球购物
Exception类的常用方法
2012/06/16 面试题
解决python 输出到csv 出现多空行的情况
2021/03/24 Python
制药工程专业毕业生推荐信
2013/12/24 职场文书
运动会演讲稿300字
2014/08/25 职场文书
招标授权委托书样本
2014/09/23 职场文书
2014年有孩子的离婚协议书范本
2014/10/08 职场文书
爱岗敬业事迹材料
2014/12/24 职场文书
2015年学雷锋活动总结
2015/02/06 职场文书
python可视化之颜色映射详解
2021/09/15 Python
聊聊CSS粘性定位sticky案例解析
2022/06/01 HTML / CSS