1. 什么是中间件
- 特指业务流程的中间处理环节,当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
- 事例:
const express = require('express') const app = express() const mw = (req, res, next) => { console.log('中间件') // next()函数实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。 next() } app.listen(80, () => { console.log('http://127.0.0.1') })
2. 中间件的作用
- 中间件的作用:多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
3. 中间件的分类
- 应用级别的中间件:
- 通过app.use()或app.get()或app.post(), 绑定到app实例上的中间件,叫做应用级别的中间件。
const express = require('express') const app = express() app.listen(80, () => { console.log('http://127.0.0.1') }) // 全局生效的中间件 const mw = (req, res, next) => { console.log('中间件') // 把流转关系交给下一个中间件 next() } app.use(mw) app.use((req, res, next) => { console.log('第二个中间件') next() }) app.get('/', (req, res) => { console.log('get /') res.send('Home page') })
// 局部生效的中间件 const mw1 = (req, res, next) => { console.log('局部中间件') next() } const mw2 = (req, res, next) => { console.log('第二个中间件') next() } app.get('/', [mw1, mw2], (req, res) => { console.log('get /') res.send('Home page') }) app.get('/user', mw1, (req, res) => { res.send('user page') }) app.get('/list', (req, res) => { res.send('list page') })
- 路由级别的中间件:
- 绑定到express.Router()实例上的中间件,叫做路由级别的中间件。
const router = express.Router() router.use((req, res, next) => { console.log("time:", Date.now()) next }) app.use('/', router)
- 错误级别的中间件
- 专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
- 错误级别的中间件必须注册在所有路由之后
app.get('/error', (req, res) => { // 抛出一个自定义错误 throw new Error('error page') res.send('Error Page') }) app.use((err, req, res, next) => { // 在服务器答应错误信息 console.log('发生错误' + err.message) // 将错误信息响应给客户端 res.send('Error:' + err.message) })
- Express内置的中间件
- express.static()快速托管静态资源的内置中间件。通过该函数可以创建一个静态资源服务器,将public目录下的图片、css文件、javascript文件对外开放。
// 可以访问public目录中文件,如http://127.0.0.1/js/test.js // app.use(express.static('./public')) // 在托管的静态资源访问路径之前挂载路径前缀 // http://127.0.0.1/public/js/test.js app.use('/public', express.static('./public'))
- express.json()解析JSON格式的请求体数据
app.use(express.json()) app.post('/user', (req, res) => { // 在服务器可以使用req.body属性来接受客户端大宋的请求数据体 // 默认情况下,如果不配置解析表单数据的中间件,req.body等于undefined console.log(req.body) res.send('OK') })
- express.urlencode()解析URL-encoded格式的请求体数据
app.use(express.urlencoded({ extended: false })) app.post('/book', (req, res) => { console.log(req.body) res.send('OK') })
- 第三方的中间件
- 非Express官方内置的,而是由第三方开发出来的中间件。
- 事例如下:
- 运行 npm i body-parser安装中间件
- 使用require导入
- 调用app.use()注册并使用中间件
const express = require('express') const app = express() const parser = require('body-parser') app.use(parser.urlencoded({ extended: false })) app.get('/book', (req, res) => { res.send('ok') }) app.post('/user', (req, res) => { console.log(req.body) res.send('ok') }) app.listen(80, () => { console.log('http://127.0.0.1') })
3. 注意事项
- 一定要在路由之前注册中间件
- 客户端发送过来的请求,可以连续调用多个中间件进行处理
- 执行完中间件业务代码之后,不要忘记调用next()
- 为了防止代码逻辑混乱,调用next()函数后不要写额外的代码
- 连续调用多个中间件时,多个中间件之间,共享req和res对象