概述

中间件函数能够访问请求对象 (req)、响应对象 (res) 以及应用程序的请求/响应循环中的下一个中间件函数。下一个中间件函数通常由名为 next 的变量来表示。
中间件函数可以执行以下任务:

  • 执行任何代码。
  • 对请求和响应对象进行更改。
  • 结束请求/响应循环。
  • 调用堆栈中的下一个中间件。

如果当前中间件函数没有结束请求/响应循环,那么它必须调用 next(),以将控制权传递给下一个中间件函数。否则,请求将保持挂起状态。
以下示例显示中间件函数调用的元素:

【20190129】express   中间件 - 图1 中间件函数适用的 HTTP 方法。
中间件函数适用的路径(路由)。
中间件函数。
中间件函数的回调自变量,按约定称为“next”。
中间件函数的 HTTP 响应自变量,按约定称为“res”。
中间件函数的 HTTP 请求自变量,按约定称为“req”。
  • 要装入中间件函数,请调用 app.use() 并指定中间件函数。 例如,以下代码在根路径 (/) 的路由之前装入 myLogger 中间件函数。使用 app.use()app.METHOD() 函数将应用层中间件绑定到应用程序对象的实例。
  • 在下面案例中,创建了一个myLogger中间件, 并且中间件使用app.use引入。
  • 应用程序每次收到请求时,会在终端上显示消息“LOGGED”。
    1. var express = require('express');
    2. var app = express();
    3. var myLogger = function (req, res, next) {
    4. console.log('LOGGED');
    5. next();
    6. };
    7. app.use(myLogger);
    8. app.get('/', function (req, res) {
    9. res.send('Hello World!');
    10. });
    11. app.listen(3000);

应用层中间件

使用 app.use()app.METHOD() 函数将应用层中间件绑定到应用程序对象的实例,其中 METHOD 是中间件函数处理的请求的小写 HTTP 方法(例如 GET、PUT 或 POST)。
此示例显示没有安装路径的中间件函数。应用程序每次收到请求时执行该函数。

  1. var app = express();
  2. app.use(function (req, res, next) {
  3. console.log('Time:', Date.now());
  4. next();
  5. });

此示例显示安装在 /user/:id 路径中的中间件函数。在 /user/:id 路径中为任何类型的 HTTP 请求执行此函数。

  1. app.use('/user/:id', function (req, res, next) {
  2. console.log('Request Type:', req.method);
  3. next();
  4. });

此示例显示一个路由及其处理程序函数(中间件系统)。此函数处理针对 /user/:id 路径的 GET 请求。

  1. app.get('/user/:id', function (req, res, next) {
  2. res.send('USER');
  3. });

以下是在安装点使用安装路径装入一系列中间件函数的示例。 它演示一个中间件子堆栈,用于显示针对 /user/:id 路径的任何类型 HTTP 请求的信息。

  1. app.use('/user/:id', function(req, res, next) {
  2. console.log('Request URL:', req.originalUrl);
  3. next();
  4. }, function (req, res, next) {
  5. console.log('Request Type:', req.method);
  6. next();
  7. });

路由处理程序使您可以为一个路径定义多个路由。以下示例为针对 /user/:id 路径的 GET 请求定义两个路由。第二个路由不会导致任何问题,但是永远都不会被调用,因为第一个路由结束了请求/响应循环。
此示例显示一个中间件子堆栈,用于处理针对 /user/:id 路径的 GET 请求。

  1. app.get('/user/:id', function (req, res, next) {
  2. console.log('ID:', req.params.id);
  3. next();
  4. }, function (req, res, next) {
  5. res.send('User Info');
  6. });
  7. // handler for the /user/:id path, which prints the user ID
  8. app.get('/user/:id', function (req, res, next) {
  9. res.end(req.params.id);
  10. });

要跳过路由器中间件堆栈中剩余的中间件函数,请调用 next('route') 将控制权传递给下一个路由。 next('route') 仅在使用 app.METHOD()router.METHOD() 函数装入的中间件函数中有效。
此示例显示一个中间件子堆栈,用于处理针对 /user/:id 路径的 GET 请求。

  1. app.get('/user/:id', function (req, res, next) {
  2. // if the user ID is 0, skip to the next route
  3. if (req.params.id == 0) next('route');
  4. // otherwise pass the control to the next middleware function in this stack
  5. else next(); //
  6. }, function (req, res, next) {
  7. // render a regular page
  8. res.render('regular');
  9. });
  10. // handler for the /user/:id path, which renders a special page
  11. app.get('/user/:id', function (req, res, next) {
  12. res.render('special');
  13. });

路由层中间件

整个目录下
路由器层中间件的工作方式与应用层中间件基本相同,差异之处在于它绑定到 express.Router() 的实例。

  1. var router = express.Router();

使用 router.use()router.METHOD() 函数装入路由器层中间件。 以下示例代码使用路由器层中间件复制以上为应用层中间件显示的中间件系统:

  1. var app = express();
  2. var router = express.Router();
  3. // a middleware function with no mount path. This code is executed for every request to the router
  4. router.use(function (req, res, next) {
  5. console.log('Time:', Date.now());
  6. next();
  7. });
  8. // a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path
  9. router.use('/user/:id', function(req, res, next) {
  10. console.log('Request URL:', req.originalUrl);
  11. next();
  12. }, function (req, res, next) {
  13. console.log('Request Type:', req.method);
  14. next();
  15. });
  16. // a middleware sub-stack that handles GET requests to the /user/:id path
  17. router.get('/user/:id', function (req, res, next) {
  18. // if the user ID is 0, skip to the next router
  19. if (req.params.id == 0) next('route');
  20. // otherwise pass control to the next middleware function in this stack
  21. else next(); //
  22. }, function (req, res, next) {
  23. // render a regular page
  24. res.render('regular');
  25. });
  26. // handler for the /user/:id path, which renders a special page
  27. router.get('/user/:id', function (req, res, next) {
  28. console.log(req.params.id);
  29. res.render('special');
  30. });
  31. // mount the router on the app
  32. app.use('/', router);

错误处理中间件

错误处理中间件始终采用四个自变量。必须提供四个自变量,以将函数标识为错误处理中间件函数。即使无需使用 next 对象,也必须指定该对象以保持特征符的有效性。否则,next 对象将被解释为常规中间件,从而无法处理错误。
错误处理中间件函数的定义方式与其他中间件函数基本相同,差别在于错误处理函数有四个自变量而不是三个,专门具有特征符 (err, req, res, next)

  1. app.use(function(err, req, res, next) {
  2. console.error(err.stack);
  3. res.status(500).send('Something broke!');
  4. });

内置中间件

自 V4.x 起,Express 不再依赖于 Connect。除 express.static 外,先前 Express 随附的所有中间件函数现在以单独模块的形式提供。请查看中间件函数的列表

express.static(root, [options])

Express 中唯一内置的中间件函数是 express.static。此函数基于 serve-static,负责提供 Express 应用程序的静态资源。
root 自变量指定从其中提供静态资源的根目录。
可选的 options 对象可以具有以下属性:

属性 描述 类型 缺省值
dotfiles 是否对外输出文件名以点(.)开头的文件。有效值包括“allow”、“deny”和“ignore” 字符串 “ignore”
etag 启用或禁用 etag 生成 布尔 true
extensions 用于设置后备文件扩展名。 数组 []
index 发送目录索引文件。设置为 false 可禁用建立目录索引。 混合 “index.html”
lastModified Last-Modified 的头设置为操作系统上该文件的上次修改日期。有效值包括 truefalse 布尔 true
maxAge 设置 Cache-Control 头的 max-age 属性(以毫秒或者 ms 格式中的字符串为单位) 数字 0
redirect 当路径名是目录时重定向到结尾的“/”。 布尔 true
setHeaders 用于设置随文件一起提供的 HTTP 头的函数。 函数

以下示例将使用了 express.static 中间件,并且提供了一个详细的’options’对象(作为示例):

  1. var options = {
  2. dotfiles: 'ignore',
  3. etag: false,
  4. extensions: ['htm', 'html'],
  5. index: false,
  6. maxAge: '1d',
  7. redirect: false,
  8. setHeaders: function (res, path, stat) {
  9. res.set('x-timestamp', Date.now());
  10. }
  11. }
  12. app.use(express.static('public', options));

对于每个应用程序,可以有多个静态目录:

  1. app.use(express.static('public'));
  2. app.use(express.static('uploads'));
  3. app.use(express.static('files'));

有关 serve-static 函数及其选项的更多详细信息,请参阅:serve-static 文档。

第三方中间件

使用第三方中间件向 Express 应用程序添加功能。
安装具有所需功能的 Node.js 模块,然后在应用层或路由器层的应用程序中将其加装入。
以下示例演示如何安装和装入 cookie 解析中间件函数 cookie-parser

  1. $ npm install cookie-parser
  1. var express = require('express');
  2. var app = express();
  3. var cookieParser = require('cookie-parser');
  4. // load the cookie-parsing middleware
  5. app.use(cookieParser());

参考资料