翻译此页面

使用中间件

Express is a routing and middleware web framework with minimal functionality of its own: an Express application is essentially a series of middleware function calls executed during the request-response cycle.

Middleware functions are functions that have access to:

  • The request object (req)
  • The response object (res)
  • The next middleware function in the application’s request-response cycle, commonly named next

中间件函数可执行下列任务:

  • 执行任意代码。
  • Modify the request and response objects.
  • 终止请求-响应周期。
  • Pass control to the next middleware function.

If a middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. 否则,请求将会被挂起。

Express 应用可以使用以下类型的中间件:

你可以通过可选的挂载路径加载应用级中间件和路由级中间件。 Multiple middleware functions can also be loaded together, which creates a middleware sub-stack at a mount point.

应用级中间件

Bind application-level middleware to an instance of the app object by using the app.use() and app.METHOD() functions, where METHOD is the lowercase HTTP method of the request that the middleware function handles, such as get, post, put, or delete.

Middleware without a mount path

The following middleware function runs every time the app receives a request:

index.cjs
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log('Time:', Date.now());
next();
});

Middleware mounted on a path

The following middleware function runs 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();
});

Route handlers

该示例展示了一条路由及其处理函数(中间件体系)。该函数处理指向 /user/:id 路径的 GET 请求。

app.get('/user/:id', (req, res) => {
res.send('USER');
});

Middleware sub-stacks

Multiple middleware functions can be loaded together at a mount point to form a middleware sub-stack. This example 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();
}
);

Multiple route handlers

路由处理程序支持为同一个路径定义多条路由。下面的示例为 /user/:id 路径的 GET 请求定义了两条路由。第二条路由不会报错,但永远不会被执行,因为第一条路由已经结束了请求-响应周期。

app.get(
'/user/:id',
(req, res, next) => {
console.log('ID:', req.params.id);
next();
},
(req, res) => {
res.send('User Info');
}
);
// handler for the /user/:id path, which prints the user ID
app.get('/user/:id', (req, res) => {
res.send(req.params.id);
});

Skipping to the next route

Call next('route') to skip the remaining middleware functions in a router middleware stack and pass control to the next route.

Note

next('route') 仅在通过 app.METHOD() 或 router.METHOD() 函数加载的中间件函数中生效。

In the following example, if the user ID is 0, the first handler skips to the next route, which sends a special response:

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) => {
// send a regular response
res.send('regular');
}
);
// handler for the /user/:id path, which sends a special response
app.get('/user/:id', (req, res) => {
res.send('special');
});

Reusable middleware arrays

Middleware functions can also be grouped into arrays for better reusability. 该示例展示了一个使用数组封装的中间件子栈,用于处理 /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) => {
res.send('User Info');
});

路由级中间件

Router-level middleware works the same way as application-level middleware, except it is bound to an instance of express.Router().

const router = express.Router();

通过 router.use() 和 router.METHOD() 函数加载路由级中间件。

下面的示例代码通过路由级中间件,复刻了上方展示的应用级中间件的中间件体系:

index.cjs
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 route
if (req.params.id === '0') next('route');
// otherwise pass control to the next middleware function in this stack
else next();
},
(req, res) => {
// render a regular page
res.render('regular');
}
);
// handler for the /user/:id path, which renders a special page
router.get('/user/:id', (req, res) => {
console.log(req.params.id);
res.render('special');
});
// mount the router on the app
app.use('/', router);

Skipping out of a router

Use next('router') to skip the rest of the router’s middleware functions and pass control back out of the router instance.

In the following example, the router only responds when the request includes an x-auth header. Otherwise, next('router') exits the router and the app responds with a 401 status:

index.cjs
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);
});

错误处理中间件

定义错误处理中间件函数的方式与其他中间件一致,唯一区别是它接收四个参数而非三个,标准函数签名为:(err, req, res, next)。

app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});

Caution

错误处理中间件始终接收四个参数。你必须传入四个参数,才能将其标识为错误处理中间件函数。即使你不需要使用 next 对象,也必须声明它,以保持函数签名不变。否则,next 对象会被解析为常规中间件,从而无法处理错误。

内置中间件

Express 包含以下内置中间件函数:

第三方中间件

使用第三方中间件可以为 Express 应用拓展功能。

先安装实现所需功能的 Node.js 模块,之后在应用级别或路由级别将其引入项目。

下面的示例演示了如何安装并加载 cookie 解析中间件 cookie-parser。

Terminal window
npm install cookie-parser
index.cjs
const express = require('express');
const app = express();
const cookieParser = require('cookie-parser');
// load the cookie-parsing middleware
app.use(cookieParser());