hello,小伙伴们,我是大家的pubdreamcc
,本篇博文出至于个人GitHub仓库node学习教程资料
,欢迎小伙伴们点赞和star
,大家的点赞是我持续更新的动力。javascript
GitHub仓库地址:node学习教程html
好了,废话很少说了,今天继续咱们express
的学习~java
今天咱们来聊一聊express中很是重要的一个概念——express middleware
(express中间件)。中间件实质就是一个函数,咱们从发送一个请求到最后服务端给回响应,在这个过程当中请求会通过多个中间件处理。下面给出一张图来理解express中间件的概念:node
这个是咱们日常自来水的处理过程图,能够看到咱们自来水从水库取出来到最后进入每一个家庭,中间通过了屡次的处理,咱们能够理解为中间的每个处理过程(方法)称之为中间件。express
中middleware
相似于上图中的每个处理过程,咱们请求到响应之间也是通过了一个或多个中间件处理,最后才是咱们看到的响应结果。git
这里咱们能够看下express
官网对中间件的分类介绍。github
express-middlewareexpress
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()
,则请求会留在该中间件中,不会继续往下执行。cookie
结果:
// 请求来了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
复制代码
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~
复制代码
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
文件丢失,请求则会进入错误处理中间件,发送错误对象的具体消息给到浏览器响应。
Built-in middleware
(内置中间件)express为咱们也提供了一些内置中间件,好比常见的开放静态资源: express.static()
等。
const express = require('express')
const app = express()
// 开放公共资源
app.use('/public/', express.static('./public'))
复制代码
Third-party middleware
(第三方中间件)一样,咱们也可使用别人封装好的第三方中间件,第三方中间件都是一个个第三方包,因此使用前须要咱们单独下载到项目中。以前的 body-parser
中间件,就是用来解析 post
请求体的数据,还有常见的像 express-session
中间件, cookie-parser
用来获取请求的cookie
数据等。第三方中间件具体能够查看 express 官方 API,这里就再也不一一罗列 。
官方推荐的第三方中间件:第三方中间件
由于文章内容是本身空闲时间编写,若是您发现有哪些错误能够在GitHub上提交 issue
,也能够在留言区发表评论,这样能够方便于后来的同窗学习,谢谢啦~