前言

Express和Koa是目前最主流的基于node的web开发框架,他们的开发者是同一班人马。貌似现在Koa更加流行,但是仍然有大量的项目在使用Express,所以我想通过这篇文章说说Express中间件的原理。

中间件的功能和分类

中间件的本质就是一个函数,在收到请求和返回相应的过程中做一些我们想做的事情。Express文档中对它的作用是这么描述的:

执行任何代码。
修改请求和响应对象。
终结请求-响应循环。
调用堆栈中的下一个中间件。

分类

Express文档中把他们分为了五类,但是他们的原理相同,只是用法不同:

应用级中间件
路由级中间件
错误处理中间件
内置中间件
第三方中间件

中间件的原理

首先我们看看中间件的用法:

var express = require('express')
var app = express();
app.use('/user', function (req, res, next) {
//TODO
next();
});
app.listen(8080)

接下来我们对比看一下下源码: 

与中间件有关的有三部分:

  • express.js继承application.js并对外暴露接口
  • application.js挂载了所有核心方法
  • router文件夹处理路由逻辑

先看express.js的代码:

这部分代码中最重要的是红色方框部分,mixin是一个第三方库。可以简单理解为继承(实际上它不是继承而是混合)。

接下来我们看application.js:

      我把文件下载下来并且删去了注释,通过这张图我们可以看出这个文件的作用是挂载了所有的方法(包括use等关键api)。

      这里面比较重要的是use方法,它的作用就是把我们用app.use注册的所有中间件和路由方法交给Router类来处理。

      那我们再看看router文件夹类的结构:

      index.js是入口文件,处理所有的路由;

      layer.js中声明了Layer类,处理每一层路由中间件或者每一个子中间件;

      router.js中声明了Router类,处理每一个子路由。

      这里面有一个子中间件的概念,对应Exprees文档中有这一句话:

另外,你还可以同时装载一系列中间件函数,从而在一个挂载点上创建一个子中间件栈。

这句话的意思是说我们可以把代码写成下面这种形式:

app.use('/user1', function fn1(req, res, next) {
// TODO
next();
}, function fn2(req, res, next) {
//TODO
next();
});
app.use('/user2', function fn3(req, res, next) {
// TODO
next();
}, function fn4(req, res, next) {
//TODO
next();
});

上面的代码给user1和user2分别创建了一个子中间件栈。这种语法的实现就是靠Layer类实现的。
      画一张图来解释上面的代码:

解释一下上面的代码和图:

      我们写了两个路由/user1和/user2,每个路由给了两个处理函数。对于这段代码,Express是这样处理的:

  1. 在index.js文件中,定义了一个stack数组,接下来会创建两个Layer放到这个stack中。
  2. route.js模块会给/user1再创建一个stack和fn1、fn2两个Layer
  3. /user2同/user1
  4. 最后,Express会从上往下执行每个Layer里的函数,对应到图上就是从上至下、从左至右的依次执行,顺序为fn1、fn2、fn3、fn4。

Express中间件原理详解的更多相关文章

  1. 淘宝JAVA中间件Diamond详解(2)-原理介绍

    淘宝JAVA中间件Diamond详解(二)---原理介绍 大家好,通过第一篇的快速使用,大家已经对diamond有了一个基本的了解.本次为大家带来的是diamond核心原理的介绍,主要包括server ...

  2. express文件上传中间件Multer详解

    express文件上传中间件Multer详解 转载自:https://www.cnblogs.com/chengdabelief/p/6580874.html   Express默认并不处理HTTP请 ...

  3. I2C 基础原理详解

    今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...

  4. Zigbee组网原理详解

    Zigbee组网原理详解 来源:互联网 作者:佚名2015年08月13日 15:57   [导读] 组建一个完整的zigbee网状网络包括两个步骤:网络初始化.节点加入网络.其中节点加入网络又包括两个 ...

  5. 块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

    CSS的可视化格式模型中具有一个非常重要地位的概念——定位方案.定位方案用以控制元素的布局,在CSS2.1中,有三种定位方案——普通流.浮动和绝对定位: 普通流:元素按照先后位置自上而下布局,inli ...

  6. SSL/TLS 原理详解

    本文大部分整理自网络,相关文章请见文后参考. SSL/TLS作为一种互联网安全加密技术,原理较为复杂,枯燥而无味,我也是试图理解之后重新整理,尽量做到层次清晰.正文开始. 1. SSL/TLS概览 1 ...

  7. 锁之“轻量级锁”原理详解(Lightweight Locking)

    大家知道,Java的多线程安全是基于Lock机制实现的,而Lock的性能往往不如人意. 原因是,monitorenter与monitorexit这两个控制多线程同步的bytecode原语,是JVM依赖 ...

  8. [转]js中几种实用的跨域方法原理详解

    转自:js中几种实用的跨域方法原理详解 - 无双 - 博客园 // // 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同 ...

  9. 节点地址的函数list_entry()原理详解

    本节中,我们继续讲解,在linux2.4内核下,如果通过一些列函数从路径名找到目标节点. 3.3.1)接下来查看chached_lookup()的代码(namei.c) [path_walk()> ...

随机推荐

  1. surrounded-regions leetcode C++

    Given a 2D board containing'X'and'O', capture all regions surrounded by'X'. A region is captured by ...

  2. 第10课 OpenGL 3D世界

    加载3D世界,并在其中漫游: 在这一课中,你将学会如何加载3D世界,并在3D世界中漫游.这一课使用第一课的代码,当然在课程说明中我只介绍改变了代码. 这一课是由Lionel Brits (βtelge ...

  3. ONVIF协议客户端

    前几天跟大家聊了一些关于ONVIF的一些基础知识,它的工作原理以及优势.今天安徽思蔷信息科技为带大家了解一下simpleonvif 百度云盘下载地址:链接:https://pan.baidu.com/ ...

  4. k8s入坑之路(13)服务迁移(定时任务 微服务 传统服务)

    定时任务迁移kubernetes 服务迁移步骤 1.安装好java 2.安装好maven 项目打包 mvn package 测试传参运行 java -cp cronjob-demo-1.0-SNAPS ...

  5. Jmeter分布式 (三)

    一.什么是分布式测试 分布式测试是指通过局域网和Internet,把分布于不同地点.独立完成特定功能的测试计算机连接起来,以达到测试资源共享.分散操作.集中管理.协同工作.负载均衡.测试过程监控等目的 ...

  6. 为 Android 编译并集成 FFmpeg 的尝试与踩坑

    前言与环境说明 随着 FFmpeg.NDK 与 Android Studio 的不断迭代,本文可能也会像我参考过的过期文章一样失效(很遗憾),但希望本文中提到的问题排查以及步骤说明能够帮到你,如果发现 ...

  7. 二.什么是Promise

    二.什么是Promise 1.理解 2.promise 的状态改变 3.promise的基本流程 4.promise的基本使用 1.理解 抽象表达: Promise 是JS 中进行异步编程的新的解决方 ...

  8. redis数据存储的细节

    redis是一个K-V NoSql非关系型数据库,redis有物种数据类型,分别是String,Hash,list,set,zset:这五种类型都是针对K-V中的V设计的. 1.总体介绍:关于redi ...

  9. 监控框架 - prometheus - 参数指标

    基于SpringBoot2.0+ Actuator metrics的监控(基于Oracle JDK9,G1) 引言 SpringBoot2在spring-boot-actuator中引入了microm ...

  10. Calendar.set方法获取前一天的当前时刻

    获取前几天的当前时刻的时间方法 Calendar cal = Calendar.getInstance(); Date date = new Date();// 获取当前时间 cal.setTime( ...