使用中间件
Express 是一个路由和中间件的网页框架,它自身的功能非常有限:一个 Express 应用本质上是一系列中间件函数的调用。
🌐 Express is a routing and middleware web framework that has minimal functionality of its own: An Express application is essentially a series of middleware function calls.
中间件 函数是可以访问请求对象(req)、响应对象(res)以及应用请求-响应周期中下一个中间件函数的函数。下一个中间件函数通常用名为 next 的变量表示。
🌐 Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.
中间件函数可以执行以下任务:
🌐 Middleware functions can perform the following tasks:
- 执行任何代码。
- 对请求和响应对象进行修改。
- 结束请求-响应循环。
- 调用堆栈中的下一个中间件函数。
如果当前的中间件函数没有结束请求-响应周期,它必须调用 next() 将控制权传递给下一个中间件函数。否则,请求将会悬挂。
🌐 If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.
一个 Express 应用可以使用以下类型的中间件:
🌐 An Express application can use the following types of middleware:
你可以加载应用级别和路由级别的中间件,并可选择挂载路径。你还可以一起加载一系列中间件函数,这将在挂载点创建中间件系统的子堆栈。
🌐 You can load application-level and router-level middleware with an optional mount path. You can also load a series of middleware functions together, which creates a sub-stack of the middleware system at a mount point.
应用层中间件
🌐 Application-level middleware
使用 app.use() 和 app.METHOD() 函数将应用级中间件绑定到 app 对象 的实例,其中 METHOD 是中间件函数处理的请求的 HTTP 方法(例如 GET、PUT 或 POST),且以小写字母表示。
🌐 Bind application-level middleware to an instance of the app object by using the app.use() and app.METHOD() functions, where METHOD is the HTTP method of the request that the middleware function handles (such as GET, PUT, or POST) in lowercase.
此示例展示了一个没有挂载路径的中间件函数。每当应用接收到请求时,该函数都会执行。
🌐 This example shows a middleware function with no mount path. The function is executed every time the app receives a request.
const express = require('express');const app = express();
app.use((req, res, next) => { console.log('Time:', Date.now()); next();});import express from 'express';
const app = express();
app.use((req, res, next) => { console.log('Time:', Date.now()); next();});import express, { type Express, type Request, type Response, type NextFunction } from 'express';
const app: Express = express();
app.use((req: Request, res: Response, next: NextFunction) => { console.log('Time:', Date.now()); next();});这个示例展示了一个挂载在 /user/:id 路径上的中间件函数。该函数会在 /user/:id 路径上的任何类型的 HTTP 请求时执行。
🌐 This example shows a middleware function mounted on the /user/:id path. The function is executed for any type of
HTTP request on the /user/:id path.
app.use('/user/:id', (req, res, next) => { console.log('Request Type:', req.method); next();});import { type Request, type Response, type NextFunction } from 'express';
app.use('/user/:id', (req: Request, res: Response, next: NextFunction) => { console.log('Request Type:', req.method); next();});此示例显示了一个路由及其处理函数(中间件系统)。该函数处理对 /user/:id 路径的 GET 请求。
🌐 This example shows a route and its handler function (middleware system). The function handles GET requests to the /user/:id path.
app.get('/user/:id', (req, res, next) => { res.send('USER');});import { type Request, type Response, type NextFunction } from 'express';
app.get('/user/:id', (req: Request, res: Response, next: NextFunction) => { res.send('USER');});这是一个在挂载点使用挂载路径加载一系列中间件函数的示例。它演示了一个中间件子栈,用于打印对 /user/:id 路径的任何类型 HTTP 请求的信息。
🌐 Here is an example of loading a series of middleware functions at a mount point, with a mount path.
It illustrates a middleware sub-stack that prints request info for any type of HTTP request to the /user/:id path.
app.use( '/user/:id', (req, res, next) => { console.log('Request URL:', req.originalUrl); next(); }, (req, res, next) => { console.log('Request Type:', req.method); next(); });import { type Request, type Response, type NextFunction } from 'express';
app.use( '/user/:id', (req: Request, res: Response, next: NextFunction) => { console.log('Request URL:', req.originalUrl); next(); }, (req: Request, res: Response, next: NextFunction) => { console.log('Request Type:', req.method); next(); });路由处理程序使你能够为一个路径定义多个路由。下面的示例为对 /user/:id 路径的 GET 请求定义了两个路由。第二个路由不会导致任何问题,但它永远不会被调用,因为第一个路由结束了请求-响应周期。
🌐 Route handlers enable you to define multiple routes for a path. The example below defines two routes for GET requests to the /user/:id path. The second route will not cause any problems, but it will never get called because the first route ends the request-response cycle.
此示例展示了一个中间件子栈,用于处理对 /user/:id 路径的 GET 请求。
🌐 This example shows a middleware sub-stack that handles GET requests to the /user/:id path.
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 IDapp.get('/user/:id', (req, res, next) => { res.send(req.params.id);});import { type Request, type Response, type NextFunction } from 'express';
app.get( '/user/:id', (req: Request, res: Response, next: NextFunction) => { console.log('ID:', req.params.id); next(); }, (req: Request, res: Response, next: NextFunction) => { res.send('User Info'); });
// handler for the /user/:id path, which prints the user IDapp.get('/user/:id', (req: Request, res: Response, next: NextFunction) => { res.send(req.params.id);});要跳过路由中间件堆栈中的其余中间件函数,请调用 next('route') 将控制权传递给下一个路由。
🌐 To skip the rest of the middleware functions from a router middleware stack, call next('route') to pass control to the next route.
Note
next('route') 仅在通过使用 app.METHOD() 或 router.METHOD() 函数加载的中间件函数中有效。
此示例展示了一个中间件子栈,用于处理对 /user/:id 路径的 GET 请求。
🌐 This example shows a middleware sub-stack that handles GET requests to the /user/:id path.
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 responseapp.get('/user/:id', (req, res, next) => { res.send('special');});import { type Request, type Response, type NextFunction } from 'express';
app.get( '/user/:id', (req: Request, res: Response, next: NextFunction) => { // 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: Request, res: Response, next: NextFunction) => { // send a regular response res.send('regular'); });
// handler for the /user/:id path, which sends a special responseapp.get('/user/:id', (req: Request, res: Response, next: NextFunction) => { res.send('special');});中间件也可以在数组中声明以实现可重用性。
🌐 Middleware can also be declared in an array for reusability.
此示例显示了一个包含中间件子堆栈的数组,该中间件子堆栈处理对 /user/:id 路径的 GET 请求
🌐 This example shows an array with a middleware sub-stack that handles GET requests to the /user/:id path
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');});import { type Request, type Response, type NextFunction } from 'express';
function logOriginalUrl(req: Request, res: Response, next: NextFunction) { console.log('Request URL:', req.originalUrl); next();}
function logMethod(req: Request, res: Response, next: NextFunction) { console.log('Request Type:', req.method); next();}
const logStuff = [logOriginalUrl, logMethod];app.get('/user/:id', logStuff, (req: Request, res: Response, next: NextFunction) => { res.send('User Info');});路由级中间件
🌐 Router-level middleware
路由级中间件的工作方式与应用级中间件相同,只是它绑定到一个 express.Router() 实例。
🌐 Router-level middleware works in the same way as application-level middleware, except it is bound to an instance of express.Router().
const router = express.Router();import express from 'express';
const router = express.Router();使用 router.use() 和 router.METHOD() 函数加载路由级别的中间件。
🌐 Load router-level middleware by using the router.use() and router.METHOD() functions.
以下示例代码通过使用路由级中间件,复制了上面所示的用于应用级中间件的中间件系统:
🌐 The following example code replicates the middleware system that is shown above for application-level middleware, by using router-level middleware:
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 routerrouter.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 pathrouter.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 pathrouter.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 pagerouter.get('/user/:id', (req, res, next) => { console.log(req.params.id); res.render('special');});
// mount the router on the appapp.use('/', router);import express from 'express';
const app = express();const router = express.Router();
// a middleware function with no mount path. This code is executed for every request to the routerrouter.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 pathrouter.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 pathrouter.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 pagerouter.get('/user/:id', (req, res, next) => { console.log(req.params.id); res.render('special');});
// mount the router on the appapp.use('/', router);import express, { type Express, type Request, type Response, type NextFunction } from 'express';
const app: Express = express();const router = express.Router();
// a middleware function with no mount path. This code is executed for every request to the routerrouter.use((req: Request, res: Response, next: NextFunction) => { console.log('Time:', Date.now()); next();});
// a middleware sub-stack shows request info for any type of HTTP request to the /user/:id pathrouter.use( '/user/:id', (req: Request, res: Response, next: NextFunction) => { console.log('Request URL:', req.originalUrl); next(); }, (req: Request, res: Response, next: NextFunction) => { console.log('Request Type:', req.method); next(); });
// a middleware sub-stack that handles GET requests to the /user/:id pathrouter.get( '/user/:id', (req: Request, res: Response, next: NextFunction) => { // 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: Request, res: Response, next: NextFunction) => { // render a regular page res.render('regular'); });
// handler for the /user/:id path, which renders a special pagerouter.get('/user/:id', (req: Request, res: Response, next: NextFunction) => { console.log(req.params.id); res.render('special');});
// mount the router on the appapp.use('/', router);要跳过路由的其余中间件函数,请调用 next('router') 将控制权传回路由实例外。
🌐 To skip the rest of the router’s middleware functions, call next('router')
to pass control back out of the router instance.
此示例展示了一个中间件子栈,用于处理对 /user/:id 路径的 GET 请求。
🌐 This example shows a middleware sub-stack that handles GET requests to the /user/:id path.
const express = require('express');const app = express();const router = express.Router();
// predicate the router with a check and bail out when neededrouter.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 throughapp.use('/admin', router, (req, res) => { res.sendStatus(401);});import express from 'express';
const app = express();const router = express.Router();
// predicate the router with a check and bail out when neededrouter.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 throughapp.use('/admin', router, (req, res) => { res.sendStatus(401);});import express, { type Express, type Request, type Response, type NextFunction } from 'express';
const app: Express = express();const router = express.Router();
// predicate the router with a check and bail out when neededrouter.use((req: Request, res: Response, next: NextFunction) => { if (!req.headers['x-auth']) return next('router'); next();});
router.get('/user/:id', (req: Request, res: Response) => { res.send('hello, user!');});
// use the router and 401 anything falling throughapp.use('/admin', router, (req: Request, res: Response) => { res.sendStatus(401);});错误处理中间件
🌐 Error-handling middleware
Caution
错误处理中间件总是接收四个参数。你必须提供四个参数来将其标识为错误处理中间件函数。即使你不需要使用 next 对象,也必须指定它以保持函数签名。否则,next 对象将被解释为普通中间件,并且无法处理错误。
🌐 Error-handling middleware always takes four arguments. You must provide four arguments to
identify it as an error-handling middleware function. Even if you don’t need to use the next
object, you must specify it to maintain the signature. Otherwise, the next object will be
interpreted as regular middleware and will fail to handle errors.
像定义其他中间件函数一样定义错误处理中间件函数,只是有四个参数而不是三个,具体的签名为 (err, req, res, next):
🌐 Define error-handling middleware functions in the same way as other middleware functions, except with four arguments instead of three, specifically with the signature (err, req, res, next):
app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('Something broke!');});import { type Request, type Response, type NextFunction } from 'express';
app.use((err: Error, req: Request, res: Response, next: NextFunction) => { console.error(err.stack); res.status(500).send('Something broke!');});有关错误处理中间件的详细信息,请参见:错误处理。
🌐 For details about error-handling middleware, see: Error handling.
内置中间件
🌐 Built-in middleware
从 4.x 版本开始,Express 不再依赖 Connect。以前包含在 Express 中的中间件函数现在位于独立的模块中;请参阅 中间件函数列表。
🌐 Starting with version 4.x, Express no longer depends on Connect. The middleware functions that were previously included with Express are now in separate modules; see the list of middleware functions.
Express 具有以下内置中间件函数:
🌐 Express has the following built-in middleware functions:
- express.static 提供静态资源,如 HTML 文件、图片等。
- express.json 解析带有 JSON 负载的传入请求。注意:仅适用于 Express 4.16.0 及以上版本
- express.urlencoded 解析带有 URL 编码负载的传入请求。注意:仅在 Express 4.16.0 及以上版本可用
第三方中间件
🌐 Third-party middleware
使用第三方中间件为 Express 应用添加功能。
🌐 Use third-party middleware to add functionality to Express apps.
安装所需功能的 Node.js 模块,然后在应用级别或路由级别加载它。
🌐 Install the Node.js module for the required functionality, then load it in your app at the application level or at the router level.
以下示例说明了如何安装和加载 cookie 解析中间件函数 cookie-parser。
🌐 The following example illustrates installing and loading the cookie-parsing middleware function cookie-parser.
npm install cookie-parseryarn add cookie-parserpnpm add cookie-parserbun add cookie-parserconst express = require('express');const app = express();const cookieParser = require('cookie-parser');
// load the cookie-parsing middlewareapp.use(cookieParser());import express from 'express';import cookieParser from 'cookie-parser';
const app = express();
// load the cookie-parsing middlewareapp.use(cookieParser());import express, { type Express } from 'express';import cookieParser from 'cookie-parser';
const app: Express = express();
// load the cookie-parsing middlewareapp.use(cookieParser());有关常用的第三方中间件函数的部分列表,请参见:第三方中间件。
🌐 For a partial list of third-party middleware functions that are commonly used with Express, see: Third-party middleware.