Express 是一个路由和中间件 Web 框架,它本身的功能很少:一个 Express 应用程序本质上是一系列中间件函数调用。
中间件函数是能够访问 请求对象 (req
)、响应对象 (res
) 以及应用程序请求-响应周期中的下一个中间件函数的函数。下一个中间件函数通常由名为 next
的变量表示。
中间件函数可以执行以下任务
如果当前中间件函数没有结束请求-响应周期,则必须调用 next()
以将控制权传递给下一个中间件函数。否则,请求将处于挂起状态。
一个 Express 应用程序可以使用以下类型的中间件
您可以使用可选的挂载路径加载应用程序级和路由器级中间件。您还可以将一系列中间件函数一起加载,这将在挂载点创建中间件系统的子堆栈。
使用 app.use()
和 app.METHOD()
函数将应用程序级中间件绑定到 app 对象 的实例,其中 METHOD
是中间件函数处理的请求的 HTTP 方法(例如 GET、PUT 或 POST)小写形式。
此示例显示了一个没有挂载路径的中间件函数。该函数在应用程序每次收到请求时都会执行。
const express = require('express')
const app = express()
app.use((req, res, next) => {
console.log('Time:', Date.now())
next()
})
此示例展示了一个安装在/user/:id
路径上的中间件函数。该函数会针对/user/:id
路径上的任何类型的 HTTP 请求执行。
app.use('/user/:id', (req, res, next) => {
console.log('Request Type:', req.method)
next()
})
此示例展示了一个路由及其处理函数(中间件系统)。该函数处理对/user/:id
路径的 GET 请求。
app.get('/user/:id', (req, res, next) => {
res.send('USER')
})
以下示例展示了在挂载点加载一系列中间件函数,并带有挂载路径。它说明了一个中间件子栈,该子栈会针对/user/:id
路径上的任何类型的 HTTP 请求打印请求信息。
app.use('/user/:id', (req, res, next) => {
console.log('Request URL:', req.originalUrl)
next()
}, (req, res, next) => {
console.log('Request Type:', req.method)
next()
})
路由处理程序允许您为一个路径定义多个路由。以下示例为对/user/:id
路径的 GET 请求定义了两个路由。第二个路由不会造成任何问题,但它永远不会被调用,因为第一个路由会结束请求-响应循环。
此示例展示了一个处理对/user/:id
路径的 GET 请求的中间件子栈。
app.get('/user/:id', (req, res, next) => {
console.log('ID:', req.params.id)
next()
}, (req, res, next) => {
res.send('User Info')
})
// handler for the /user/:id path, which prints the user ID
app.get('/user/:id', (req, res, next) => {
res.send(req.params.id)
})
要跳过路由中间件栈中剩余的中间件函数,请调用next('route')
将控制权传递给下一个路由。注意:next('route')
仅在使用app.METHOD()
或router.METHOD()
函数加载的中间件函数中有效。
此示例展示了一个处理对/user/:id
路径的 GET 请求的中间件子栈。
app.get('/user/:id', (req, res, next) => {
// if the user ID is 0, skip to the next route
if (req.params.id === '0') next('route')
// otherwise pass the control to the next middleware function in this stack
else next()
}, (req, res, next) => {
// send a regular response
res.send('regular')
})
// handler for the /user/:id path, which sends a special response
app.get('/user/:id', (req, res, next) => {
res.send('special')
})
中间件也可以在数组中声明,以实现可重用性。
此示例展示了一个包含处理对/user/:id
路径的 GET 请求的中间件子栈的数组。
function logOriginalUrl (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}
function logMethod (req, res, next) {
console.log('Request Type:', req.method)
next()
}
const logStuff = [logOriginalUrl, logMethod]
app.get('/user/:id', logStuff, (req, res, next) => {
res.send('User Info')
})
路由级中间件的工作方式与应用程序级中间件相同,只是它绑定到express.Router()
的实例上。
const router = express.Router()
使用router.use()
和router.METHOD()
函数加载路由级中间件。
以下示例代码使用路由级中间件复制了上面显示的应用程序级中间件的中间件系统。
const express = require('express')
const app = express()
const router = express.Router()
// a middleware function with no mount path. This code is executed for every request to the router
router.use((req, res, next) => {
console.log('Time:', Date.now())
next()
})
// a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path
router.use('/user/:id', (req, res, next) => {
console.log('Request URL:', req.originalUrl)
next()
}, (req, res, next) => {
console.log('Request Type:', req.method)
next()
})
// a middleware sub-stack that handles GET requests to the /user/:id path
router.get('/user/:id', (req, res, next) => {
// if the user ID is 0, skip to the next router
if (req.params.id === '0') next('route')
// otherwise pass control to the next middleware function in this stack
else next()
}, (req, res, next) => {
// render a regular page
res.render('regular')
})
// handler for the /user/:id path, which renders a special page
router.get('/user/:id', (req, res, next) => {
console.log(req.params.id)
res.render('special')
})
// mount the router on the app
app.use('/', router)
要跳过路由的剩余中间件函数,请调用next('router')
将控制权传递回路由实例之外。
此示例展示了一个处理对/user/:id
路径的 GET 请求的中间件子栈。
const express = require('express')
const app = express()
const router = express.Router()
// predicate the router with a check and bail out when needed
router.use((req, res, next) => {
if (!req.headers['x-auth']) return next('router')
next()
})
router.get('/user/:id', (req, res) => {
res.send('hello, user!')
})
// use the router and 401 anything falling through
app.use('/admin', router, (req, res) => {
res.sendStatus(401)
})
错误处理中间件始终接受四个参数。您必须提供四个参数才能将其识别为错误处理中间件函数。即使您不需要使用next
对象,也必须指定它以保持签名。否则,next
对象将被解释为常规中间件,并且无法处理错误。
定义错误处理中间件函数的方式与其他中间件函数相同,只是有四个参数而不是三个,具体来说是签名(err, req, res, next)
。
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).send('Something broke!')
})
有关错误处理中间件的详细信息,请参阅:错误处理.
从 4.x 版本开始,Express 不再依赖于Connect。以前包含在 Express 中的中间件函数现在位于单独的模块中;请参阅中间件函数列表.
Express 具有以下内置中间件函数
使用第三方中间件为 Express 应用程序添加功能。
安装所需功能的 Node.js 模块,然后在应用程序级别或路由器级别加载它。
以下示例演示了安装和加载 cookie 解析中间件函数 cookie-parser
。
$ npm install cookie-parser
const express = require('express')
const app = express()
const cookieParser = require('cookie-parser')
// load the cookie-parsing middleware
app.use(cookieParser())
有关通常与 Express 一起使用的第三方中间件函数的部分列表,请参阅:第三方中间件。