浅谈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 相关文章推荐
自动完成JS类(纯JS, Ajax模式)
Mar 12 Javascript
JavaScript 图片预览效果 推荐
Dec 22 Javascript
jQuery队列操作方法实例
Jun 11 Javascript
jQuery实现响应浏览器缩放大小并改变背景颜色
Oct 31 Javascript
jQuery AjaxUpload 上传图片代码
Feb 02 Javascript
使用PHP+JavaScript将HTML页面转换为图片的实例分享
Apr 18 Javascript
js利用正则表达式检验输入内容是否为网址
Jul 05 Javascript
jquery实现简单自动轮播图效果
Jul 29 jQuery
vue 需求 data中的数据之间的调用操作
Aug 05 Javascript
JavaScript用document.write()输出换行的示例代码
Nov 26 Javascript
Vue如何实现变量表达式选择器
Feb 18 Vue.js
pnpm对npm及yarn降维打击详解
Aug 05 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 session_start()出错原因分析及解决方法
2013/10/28 PHP
PHP curl CURLOPT_RETURNTRANSFER参数的作用使用实例
2015/02/07 PHP
PHP使用GETDATE获取当前日期时间作为一个关联数组的方法
2015/03/19 PHP
Laravel学习笔记之Artisan命令生成自定义模板的方法
2018/11/22 PHP
微信公众平台开发教程①获取用户Openid及个人信息图文详解
2019/04/10 PHP
javascript 表单的友好用户体现
2009/01/07 Javascript
jQuery图片的展开和收缩实现代码
2013/04/16 Javascript
使用js操作css实现js改变背景图片示例
2014/03/10 Javascript
如何使用HTML5地理位置定位功能
2015/04/27 Javascript
jquery右下角自动弹出可关闭的广告层
2015/05/08 Javascript
使用AngularJS和PHP的Laravel实现单页评论的方法
2015/06/19 Javascript
jQuery EasyUI 布局之动态添加tabs标签页
2015/11/18 Javascript
详解基于javascript实现的苹果系统底部菜单
2016/12/02 Javascript
Angular 常用指令实例总结整理
2016/12/13 Javascript
详解使用Vue.Js结合Jquery Ajax加载数据的两种方式
2017/01/10 Javascript
JSONP跨域请求
2017/03/02 Javascript
Vue2.0基于vue-cli+webpack同级组件之间的通信教程(推荐)
2017/09/14 Javascript
react-router 路由切换动画的实现示例
2018/12/03 Javascript
15分钟深入了解JS继承分类、原理与用法
2019/01/19 Javascript
layui的表单验证支持ajax判断用户名是否重复的实例
2019/09/06 Javascript
jQuery实现飞机大战小游戏
2020/07/05 jQuery
Vue文本模糊匹配功能如何实现
2020/07/30 Javascript
[00:34]TI7不朽珍藏III——纯金地穴编织者饰品展示
2017/07/15 DOTA
[01:04:49]KG vs LGD 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
python3生成随机数实例
2014/10/20 Python
Python访问MySQL封装的常用类实例
2014/11/11 Python
python绘制双柱形图代码实例
2017/12/14 Python
python使用xpath中遇到:到底是什么?
2018/01/04 Python
利用pandas进行大文件计数处理的方法
2018/07/25 Python
python 日期排序的实例代码
2019/07/11 Python
详解Python Opencv和PIL读取图像文件的差别
2019/12/27 Python
jupyter notebook 参数传递给shell命令行实例
2020/04/10 Python
医药大学生求职简历的自我评价
2013/10/17 职场文书
个人欠款担保书
2014/05/20 职场文书
TypeScript中条件类型精读与实践记录
2021/10/05 Javascript
MySQL数据库Innodb 引擎实现mvcc锁
2022/05/06 MySQL