浅谈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 相关文章推荐
web css实现整站样式互相切换
Oct 29 Javascript
兼容主流浏览器的iframe自适应高度js脚本
Jan 10 Javascript
JS完整获取IE浏览器信息包括类型、版本、语言等等
May 22 Javascript
js实现文本框选中的方法
May 26 Javascript
javascript实现的简单计时器
Jul 19 Javascript
jQuery实现Tab菜单滚动切换的方法
Sep 21 Javascript
jQuery中的siblings用法实例分析
Dec 24 Javascript
JS获取复选框的值,并传递到后台的实现方法
May 30 Javascript
原生js实现密码输入框值的显示隐藏
Jul 17 Javascript
微信小程序仿知乎实现评论留言功能
Nov 28 Javascript
小程序按钮避免多次调用接口和点击方案实现(不用showLoading)
Apr 15 Javascript
vue print.js打印支持Echarts图表操作
Nov 13 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 allow_url_include的应用和解释
2010/04/22 PHP
PHP图片处理之使用imagecopy函数添加图片水印实例
2014/11/19 PHP
PHP使用内置dir类实现目录遍历删除
2015/03/31 PHP
使用php从身份证号中获取一系列线索(星座、生肖、生日等)
2016/05/11 PHP
Laravel中七个非常有用但很少人知道的Carbon方法
2017/09/21 PHP
discuz论坛更换域名,详细文件修改步骤
2020/12/09 PHP
JavaScript 学习笔记(十二) dom
2010/01/21 Javascript
深入理解JavaScript系列(3) 全面解析Module模式
2012/01/15 Javascript
js跑马灯代码(自写)
2013/04/17 Javascript
JSCode all of Brower 全局屏蔽网页右键功能 具体实现
2013/06/05 Javascript
Jquery获得控件值的三种方法总结
2014/02/13 Javascript
jquery学习总结(超级详细)
2014/09/04 Javascript
详解JavaScript正则表达式中的global属性的使用
2015/06/16 Javascript
jQuery实现TAB风格的全国省份城市滑动切换效果代码
2015/08/24 Javascript
基于JS实现Android,iOS一个手势动画效果
2016/04/27 Javascript
Angular 2 利用Router事件和Title实现动态页面标题的方法
2017/08/23 Javascript
mui上拉加载更多下拉刷新数据的封装过程
2017/11/03 Javascript
浅析Vue中method与computed的区别
2018/03/06 Javascript
使用JS实现导航切换时高亮显示的示例讲解
2018/08/22 Javascript
ES6 async、await的基本使用方法示例
2020/06/06 Javascript
解决VUE mounted 钩子函数执行时 img 未加载导致页面布局的问题
2020/07/27 Javascript
js 压缩图片的示例(只缩小体积,不更改图片尺寸)
2020/10/21 Javascript
python实现顺序表的简单代码
2018/09/28 Python
Python获取基金网站网页内容、使用BeautifulSoup库分析html操作示例
2019/06/04 Python
浅谈Python 递归算法指归
2019/08/22 Python
Python While循环语句实例演示及原理解析
2020/01/03 Python
Python实现京东抢秒杀功能
2021/01/25 Python
HTML5如何为形状图上颜色怎么绘制具有颜色和透明度的矩形
2014/06/23 HTML / CSS
详解window.open被浏览器拦截的解决方案
2019/07/18 HTML / CSS
I.T中国官网:精选时尚设计师单品网购平台
2018/03/26 全球购物
澳大利亚家用电器在线商店:Billy Guyatts
2020/05/05 全球购物
中文专业毕业生自荐信
2013/10/28 职场文书
公司活动方案范文
2014/03/06 职场文书
霸气押韵的班级口号
2014/06/09 职场文书
PO模式在selenium自动化测试框架的优势
2022/03/20 Python
Java设计模式中的命令模式
2022/04/28 Java/Android