Express中的中间件

100 阅读3分钟

概念

Express的本质就是一个基于路由和中间件的Web框架,Express的本质就是一系列中间件函数的调用

在Express中 中间件是一个接收 请求体 和 响应头的 回调函数

简单来说,中间件就是放在请求和响应之间的一个回调函数,用来处理请求的中间步骤

image-20250620141609903

中间件的匹配规则是:

  1. Express 会找到第一个匹配的中间件并执行。
  2. 如果中间件直接返回了结果,那么请求处理就结束了。
  3. 如果没有返回结果,可以通过 next() 传递控制权到下一个中间件,继续处理请求并返回结果。

通用中间件

import express from 'express'const app = express()
​
// 第一个参数是request对象,第二个参数是response对象, 第三个参数是next函数
// + request对象: 请求体对象 => 基于 http 模块的 request 对象扩展而来
// + response对象: 响应体对象 => 基于 http 模块的 response 对象扩展而来
// + next函数: 用于调用下一个中间件
app.use((req, res, next) => {
  // 在中间件回调中可以执行任何操作
  // 满足条件的中间件会被依次回调。在这个过程中,请求体和响应头都是同一个
  // 因此此时 对应的请求或响应并没有结束,还是同一个
  req.name = '张三'
  // 调用下一个中间件
  next()
})
​
app.get('/', (req, res) => {
  // 中间件处理完成后要么传递给下一个中间件,要么结束响应。
  // 否则客户端会一直处于挂起状态,即一直处于加载中,直到超时
  res.send(`hello ${req.name}`)
})
​
app.listen(3000, () => {
  console.log('Server is running on port 3000')
})

路径中间件

import express from 'express'const app = express()
​
// 通过 app.use 注册 通用中间件
// 通用中间件: 可以匹配所有请求路径和请求方法的中间件
app.use((req, res, next) => {
  console.log('通用中间件')
  // 通过 next 调用下一个 满足条件的 中间件 => next 方法是无参的
  // 若不调用next(),则后续的中间件将不会被执行
  next()
})
​
// 只要路径匹配,就会执行这个中间件 「 无论使用的是那种请求方法 」
app.use('/', (req, res, next) => {
  console.log('路径匹配中间件')
  next()
})
​
// 通过 app.get、app.post、app.put、app.delete等方法 注册 路由中间件
// 路由中间件: 只能匹配特定请求路径和请求方法的中间件
app.get('/', (req, res) => {
  console.log('路由中间件')
  res.send('hello world')
})
​
app.listen(3000, () => {
  console.log('Server is running on port 3000')
})

路由中间件

import express from 'express'const app = express()
app.get('/', (req, res) => {
  // 获取请求路径
  console.log('url', req.url) // => /?name=Klaus&age=23
  // 获取请求路径中的路径部分
  console.log('path', req.path) // => /
  // 获取请求方法
  console.log('method', req.method) // => GET
​
  res.send('hello world')
})
​
app.listen(3000, () => {
  console.log('Server is running on port 3000')
})

一次注册多个中间件

这样做的好处是,你可以将复杂操作拆分成多个中间件,依次执行。「 单一职责原则 」

如果每个中间件里调用next(),后面的中间件会依次执行。

如果没有调用next(),后面的中间件就不会被执行。

这是将复杂操作拆分成多个中间件的一种常见方法,特别适用于需要多步验证和数据处理的情况。

import express from 'express'const app = express()
​
// 每种类型中间件都可以一次注册多个中间件
// 这些中间件会整合为数组并被依次回调
app.get('/', (req, res, next) => {
  console.log('中间件1')
  next()
}, (req, res, next) => {
  console.log('中间件2')
  next()
}, (req, res, next) => {
  console.log('中间件3')
  res.send('hello world')
})
​
app.listen(3000, () => {
  console.log('Server is running on port 3000')
})

链式调用

import express from 'express'const app = express()
​
// 每个中间件返回的都是 应用实例
// 因此可以链式调用
app
 .use((req, res, next) => {
  console.log('通用中间件')
  next()
})
.use('/', (req, res, next) => {
  console.log('路径匹配中间件')
  next()
})
.get('/', (req, res) => {
  console.log('路由中间件')
  res.send('hello world')
})
​
app.listen(3000, () => {
  console.log('Server is running on port 3000')
})

兜底页面

可以将一个 通用中间件 放在所有路由的最后边,从而进行路由兜底

app.use((req, res, next) => {
  // 通过 status 方法 设置 响应码
  res.status(404).json({ error: 'Not Found' });
});