写在前面

hello,小伙伴们,我是你们的pubdreamcc,本篇博文出至于我的GitHub仓库node学习教程资料,欢迎小伙伴们点赞和star,你们的点赞是我持续更新的动力。

GitHub仓库地址:node学习教程

好了,废话不多说了,今天继续我们express的学习~

开篇

今天我们来聊一聊express中非常重要的一个概念——express middleware (express中间件)。中间件实质就是一个函数,我们从发送一个请求到最后服务端给回响应,在这个过程中请求会经过多个中间件处理。下面给出一张图来理解express中间件的概念:

这个是我们平常自来水的处理过程图,可以看到我们自来水从水库取出来到最后进入每个家庭,中间经过了多次的处理,我们可以理解为中间的每一个处理过程(方法)称之为中间件。expressmiddleware类似于上图中的每一个处理过程,我们请求到响应之间也是经过了一个或多个中间件处理,最后才是我们看到的响应结果。

中间件的分类和使用

这里我们可以看下express官网对中间件的分类介绍。

express-middleware

  1. Application-level middleware(应用程序级别中间件)

应用程序级别中间件又分为以下三种情况。

  • 不管请求地址和请求方法,任何请求都能进入。
const app = express()

app.use((req, res, next) => {
console.log('请求来了1~')
next() // 调用next(),请求会去下一个紧挨着的匹配的中间件
}) app.use((req, res, next) => {
console.log('请求来了2~')
// 没有调用next(),请求会留在该中间件中
}) app.use((req, res, next) => {
console.log('请求来了3~')
})

这里配置了三个应用程序级别的中间件,当客户端发一个请求,就会从上至下首先进入第一个中间件处理,接着看是否内部调用next()来决定请求是否往下执行。

我们在服务端请求处理函数中还可以传入第三个参数:next,如果在函数体中调用next(),则请求会在经过该中间件处理后继续向下找最近的那个匹配成功的中间件,并且进入该中间件处理。如果没有调用next(),则请求会留在该中间件中,不会继续往下执行。

结果:

// 请求来了1

// 请求来了2
  • 特定请求路径的任何类型请求都能进入
const app = express()

app.use('/a', (req, res, next) => {
console.log('请求来了1~')
next() // 调用next(),请求会去下一个紧挨着的匹配的中间件
}) app.use('/b', (req, res, next) => {
console.log('请求来了2~')
}) app.use('/a', (req, res, next) => {
console.log('请求来了3~')
})

同样的,这里也配置了三个中间件,因为在中间件中规定了请求路径,所以只能是以 /a 开头 的请求才能进入第一个中间件处理。因为在第一个中间件内部调用了next()方法,所以请求会继续往下找匹配的中间件,第二个中间请求地址不匹配,所以进入第三个中间件处理。

结果:

// 请求来了1

// 请求来了3
  • 特定请求方法和特定请求地址的请求能够进入

对于这种情况我们最为熟悉,之前已经练习过多次。

const app = express()

app.get('/a', (req, res, next) => {
console.log('请求来了1~')
next() // 调用next(),请求会去下一个紧挨着的匹配的中间件
}) app.post('/a', (req, res, next) => {
console.log('请求来了2~')
}) app.get('/a', (req, res, next) => {
console.log('请求来了3~')
})

同样以上面的例子,写三个中间件。这里规定了必须以 GET 请求而且请求路径为:/a的请求会被第一个中间件处理,因为内部调用了 next(),所以请求会继续往下找临近的匹配的中间件,第二个中间件规定的请求方法为:POST,所以进入第三个中间件处理。

结果:

// 请求来了1

// 请求来了3
  1. Router-level middleware(路由级别中间件)

路由级别的中间件与上面应用程序级别中间件的工作方式类似,只不过把路由模块单独提取出来,最后通过把路由容器挂载到 app 服务器实例上即可。

  • 不管请求地址和请求方法,任何请求都能进入。
const router = express.Router()

router.use((req, res, next) => {
console.log('请求来了1~')
next() // 调用next(),请求会去下一个紧挨着的匹配的中间件
}) router.use((req, res, next) => {
console.log('请求来了2~')
// 没有调用next(),请求停留在此,不会继续往下找了
}) router.use((req, res, next) => {
console.log('请求来了3~')
})

结果:

// 请求来了1~

// 请求来了2~
  • 特定请求路径的任何类型请求都能进入
const router = express.Router()

router.use('/a', (req, res, next) => {
console.log('请求来了1~')
next() // 调用next(),请求会去下一个紧挨着的匹配的中间件
}) router.use('/b', (req, res, next) => {
console.log('请求来了2~')
}) router.use('/a', (req, res, next) => {
console.log('请求来了3~')
})

结果:

// 请求来了1~

// 请求来了3~
  • 特定请求方法和特定请求地址的请求能够进入
const router = express.Router()

router.get('/a', (req, res, next) => {
console.log('请求来了1~')
next() // 调用next(),请求会去下一个紧挨着的匹配的中间件
}) router.post('/a', (req, res, next) => {
console.log('请求来了2~')
}) router.get('/a', (req, res, next) => {
console.log('请求来了3~')
})

结果:

// 请求来了1~

// 请求来了3~
  1. Error-handling middleware(全局错误处理中间件)

在实际开发中,往往我们需要统一来处理异步操作发生的错误,这个时候我们需要在项目中配置一个全局错误处理中间件即可。

const express = require('express')

const fs = require('fs')

const app = express()

app.get('/', (req, res, next) => {
fs.readFile('./index.html', (err, date) => {
if (err) {
// 如果异步读取文件错误,把错误对象传给next()
return next(err)
}
// 成功,发送读取后的数据,浏览器渲染页面
res.send(data)
})
}) // 配置一个全局错误处理中间件,注意这里接收四个参数,一个都不能少,否则会出错 app.use((err, req, res, next) => {
// err参数为前面next()方法接收到的错误对象
res.status(500).send(err.message)
})

通过配置一个全局错误处理中间件,我们可以统一处理请求发送错误时服务端的响应。这里一定要给错误处理中间件的处理函数 四个参数, 切记。在应用程序级别的中间件 app.get() 中,当异步读取文件失败时,记得要把错误对象传递给next() 方法 。通过这样,一旦 index.html 文件丢失,请求则会进入错误处理中间件,发送错误对象的具体消息给到浏览器响应。

  1. Built-in middleware(内置中间件)

express为我们也提供了一些内置中间件,比如常见的开放静态资源: express.static()等。

const express = require('express')

const app = express()

// 开放公共资源
app.use('/public/', express.static('./public'))
  1. Third-party middleware(第三方中间件)

同样,我们也可以使用别人封装好的第三方中间件,第三方中间件都是一个个第三方包,所以使用前需要我们单独下载到项目中。之前的 body-parser 中间件,就是用来解析 post 请求体的数据,还有常见的像 express-session 中间件, cookie-parser用来获取请求的 cookie 数据等。第三方中间件具体可以查看 express 官方 API,这里就不再一一罗列 。

官方推荐的第三方中间件:第三方中间件

写在后面

因为文章内容是自己空闲时间编写,如果您发现有哪些错误可以在GitHub上提交 issue ,也可以在留言区发表评论,这样可以方便于后来的同学学习,谢谢啦~

可能是全网最详细的express--middleware的更多相关文章

  1. 全网最详细的IDEA、Eclipse和MyEclipse之间于Java web项目发布到Tomcat上运行成功的对比事宜【博主强烈推荐】【适合普通的还是Maven方式创建的】(图文详解)

    不多说,直接上干货! IDEA [适合公司业务]全网最详细的IDEA里如何正确新建[普通或者Maven]的Java web项目并发布到Tomcat上运行成功[博主强烈推荐](类似eclipse里同一个 ...

  2. 【适合公司业务】全网最详细的IDEA里如何正确新建【普通或者Maven】的Java web项目并发布到Tomcat上运行成功【博主强烈推荐】(类似eclipse里同一个workspace下【多个子项目】并存)(图文详解)

    不多说,直接上干货! 首先,大家要明确,IDEA.Eclipse和MyEclipse等编辑器之间的新建和运行手法是不一样的. 如果是在Myeclipse里,则是File -> new -> ...

  3. 全网最详细的Eclipse和MyEclipse里对于Java web项目发布到Tomcat上运行成功的对比事宜【博主强烈推荐】【适合普通的还是Maven方式创建的】(图文详解)

    不多说,直接上干货! 首先,大家要明确,IDEA.Eclipse和MyEclipse等编辑器之间的新建和运行手法是不一样的. 全网最详细的MyEclipse里如何正确新建普通的Java web项目并发 ...

  4. 全网最详细的IDEA里如何正确新建普通的Java web项目并发布到Tomcat上运行成功【博主强烈推荐】(类似eclipse里同一个workspace下【一个子项目】并存)(图文详解)

    不多说,直接上干货! 首先,大家要明确,IDEA.Eclipse和MyEclipse等编辑器之间的新建和运行手法是不一样的. 如果是在Myeclipse里,则是File -> new -> ...

  5. 全网最详细的Eclipse里如何正确新建普通的Java web项目并发布到Tomcat上运行成功【博主强烈推荐】(图文详解)

    不多说,直接上干货! 首先,大家要明确,IDEA.Eclipse和MyEclipse等编辑器之间的新建和运行手法是不一样的. 如果是在Myeclipse里,则是File -> new -> ...

  6. 全网最详细的MyEclipse里如何正确新建普通的Java web项目并发布到Tomcat上运行成功【博主强烈推荐】(图文详解)

    不多说,直接上干货! 首先,大家要明确,IDEA.Eclipse和MyEclipse等编辑器之间的新建和运行手法是不一样的. 如果是在eclipse里,则是File -> new ->  ...

  7. 全网最详细的Windows系统里Oracle 11g R2 Client(64bit)的下载与安装(图文详解)

    不多说,直接上干货! 环境: windows10系统(64位) 最好先安装jre或jdk(此软件用来打开oracle自带的可视化操作界面,不装也没关系:可以安装plsql,或者直接用命令行操作) Or ...

  8. 全网最详细的Windows系统里Oracle 11g R2 Client客户端(64bit)安装后的初步使用(图文详解)

    不多说,直接上干货! 前期博客 全网最详细的Windows系统里Oracle 11g R2 Client(64bit)的下载与安装(图文详解) 命令行方式测试安装是否成功 1)   打开服务(cmd— ...

  9. 全网最详细的Windows系统里Oracle 11g R2 Database(64bit)安装后的初步使用(图文详解)

    不多说,直接上干货! 前期博客 全网最详细的Windows系统里Oracle 11g R2 Database(64bit)的下载与安装(图文详解) 命令行方式测试安装是否成功 1)   打开服务(cm ...

  10. 全网最详细的Windows系统里Oracle 11g R2 Database(64bit)的完全卸载(图文详解)

    不多说,直接上干货! 前期博客 全网最详细的Windows系统里Oracle 11g R2 Database(64bit)的下载与安装(图文详解) 若你不想用了,则可安全卸载. 完全卸载Oracle ...

随机推荐

  1. HTML5一些特殊效果分享地址集合

    页面预加载图片原生js: http://www.cnblogs.com/st-leslie/articles/5274568.html HTML5 FileReader读取本地文件: http://n ...

  2. python3 输入某年某月某日,判断这一天是这一年的第几天?

    题目 输入某年某月某日,判断这一天是这一年的第几天? 程序分析 特殊情况,闰年时需考虑二月多加一天. 代码: import calendar year = int(input("Year:& ...

  3. 【HIHOCODER 1420】 Bigint Multiplication

    描述 Given 2 nonnegative integers a and b, calculate a × b. 输入 One line with 2 integers a and b separa ...

  4. Linux中同步与异步、阻塞与非阻塞概念以及五种IO模型

    1.概念剖析 相信很多从事linux后台开发工作的都接触过同步&异步.阻塞&非阻塞这样的概念,也相信都曾经产生过误解,比如认为同步就是阻塞.异步就是非阻塞,下面我们先剖析下这几个概念分 ...

  5. Win7通知区域的图标怎么去除?

    由于本人有洁癖,最近在用win7的时候,很收不了已经卸载了的一些软件,在win7右下角的通知区域图标中还留有痕迹,于是上网查找了下解决方案. 用以下方法完美解决问题. 这里依然是以注册表的修改方法为主 ...

  6. 【水】ZYH记

    我从十二岁起,便在sdoj的蒟蒻餐厅里当伙计,root说,样子太傻,怕侍候不了专职切题,就在外面做点事罢.外面的调试管理,虽然容易说话,但唠唠叨叨缠夹不清的也很不少.他们往往要亲眼看着一个字一个字编译 ...

  7. python随机数的产生

    导入 random模块  >>> import random 1.  random.random random.random()用于生成一个0到1的随机浮点数: 0 <= n ...

  8. 2章 perl标量变量

    标量变量 单单存储一个值得变量   ,单个标量值 $name   为变量  区分大小写 $barney=$barney*2   第一次  取值  等号右边    :第二次  赋值 等号左边 双目操作符 ...

  9. 【LeetCode】Balanced Binary Tree(平衡二叉树)

    这道题是LeetCode里的第110道题. 题目要求: 给定一个二叉树,判断它是否是高度平衡的二叉树. 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1. ...

  10. [python学习篇][书籍学习][python standrad library][内建类型]之数值

    数值类型 — int, float, long, complex 有四种不同的数值类型:普通整数.长整数.浮点数和复数 普通整数(或者简称整数)使用C中的long实现,其精度至少为32位(sys.ma ...