中间件
中间件
中间件函数能够接受到请求对象(req
)、响应对象(res
) 以及应用程序的请求/响应循环中的下一个中间件函数作为参数。下一个中间件函数通常由名为 next
的变量来表示。
中间件函数可以执行以下任务:
- 执行任何代码。
- 对请求和响应对象进行更改。
- 结束请求/响应循环。
- 调用堆栈中的下一个中间件。
如果当前中间件函数没有结束请求/响应循环,那么它必须调用 next()
,以将控制权传递给下一个中间件函数。否则,请求将保持挂起状态。
简单示例
以下是名为“myLogger”的中间件函数的简单示例。此函数仅在应用程序的请求通过它时显示“LOGGED”。
var myLogger = function (req, res, next) {
console.log('LOGGED');
next();
};
请注意以上对
next()
的调用。调用此函数时,将调用应用程序中的下一个中间件函数。next()
函数不是 Node.js 或 Express API 的一部分,而是传递给中间件函数的第三自变量。next()
函数可以命名为任何名称,但是按约定,始终命名为“next”。为了避免混淆,请始终使用此约定。
要加载中间件,请调用 app.use()
并指定中间件函数。 例如,以下代码在根路径 (/) 的路由之前装入 myLogger
中间件函数。
var express = require('express');
var app = express();
var myLogger = function (req, res, next) {
console.log('LOGGED');
next();
};
app.use(myLogger);
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.listen(3000);
应用程序每次收到请求时,都会在终端上显示消息“LOGGED”。
中间件加载顺序很重要:首先加载的中间件也会首先被执行。
如果在根路径的路由之后装入 myLogger
,那么请求永远都不会到达该函数,应用程序也不会显示“LOGGED”,因为根路径的路由处理程序终止了请求/响应循环。
中间件函数 myLogger
只是显示消息,然后通过调用 next()
函数将请求传递到堆栈中的下一个中间件函数。
下一个示例将名为 requestTime
的属性添加到请求对象。我们将此中间件函数命名为“requestTime”。
var requestTime = function (req, res, next) {
req.requestTime = Date.now();
next();
};
现在,为该应用程序加载 requestTime
中间件。此外,根路径路由的回调函数使用由中间件函数添加到 req
(请求对象)的属性。
var express = require('express');
var app = express();
var requestTime = function (req, res, next) {
req.requestTime = Date.now();
next();
};
app.use(requestTime);
app.get('/', function (req, res) {
var responseText = 'Hello World!';
responseText += 'Requested at: ' + req.requestTime + '';
res.send(responseText);
});
app.listen(3000);
您向应用程序根发出请求时,此应用程序当前在浏览器中显示请求的时间戳。
因为您拥有请求对象、响应对象、堆栈中的下一个中间件函数以及整个 Node.js API 的访问权,所以中间件函数的可能性是无穷的。
Express 应用程序可以使用以下类型的中间件:
您可以使用可选安装路径来加载应用层和路由器层中间件。 还可以将一系列中间件函数一起加载,这样会在安装点创建中间件系统的子堆栈。
应用层中间件
使用 app.use()
和 app.METHOD()
函数将应用层中间件绑定到 Express
的实例,其中 METHOD
是中间件函数处理的请求的小写 HTTP 方法(例如 GET、PUT 或 POST)。
此示例显示没有安装路径的中间件函数。应用程序每次收到请求时执行该函数。
var app = express();
app.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
此示例显示安装在 /user/:id
路径中的中间件函数。在 /user/:id
路径中为任何类型的 HTTP 请求执行此函数。
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
此示例显示一个路由及其处理程序函数(中间件系统)。此函数处理针对 /user/:id
路径的 GET 请求。
app.get('/user/:id', function (req, res, next) {
res.send('USER');
});
以下是在安装点使用安装路径装入一系列中间件函数的示例。 它演示一个中间件子堆栈,用于显示针对 /user/:id
路径的任何类型 HTTP 请求的信息。
app.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
路由处理程序使您可以为一个路径定义多个路由。以下示例为针对 /user/:id
路径的 GET 请求定义两个路由。第二个路由不会导致任何问题,但是永远都不会被调用,因为第一个路由结束了请求/响应循环。
此示例显示一个中间件子堆栈,用于处理针对 /user/:id
路径的 GET 请求。
app.get('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id);
next();
}, function (req, res, next) {
res.send('User Info');
});
// handler for the /user/:id path, which prints the user ID
app.get('/user/:id', function (req, res, next) {
res.end(req.params.id);
});
要跳过路由器中间件堆栈中剩余的中间件函数,请调用 next('route')
将控制权传递给下一个路由。 注:next('route')
仅在使用 app.METHOD()
或 router.METHOD()
函数装入的中间件函数中有效。
此示例显示一个中间件子堆栈,用于处理针对 /user/:id
路径的 GET 请求。
app.get('/user/:id', function (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(); //
}, function (req, res, next) {
// render a regular page
res.render('regular');
});
// handler for the /user/:id path, which renders a special page
app.get('/user/:id', function (req, res, next) {
res.render('special');
});
路由器层中间件
路由器层中间件的工作方式与应用层中间件基本相同,差异之处在于它绑定到 express.Router()
的实例。
var router = express.Router();
使用 router.use()
和 router.METHOD()
函数装入路由器层中间件。 以下示例代码使用路由器层中间件复制以上为应用层中间件显示的中间件系统:
var app = express();
var router = express.Router();
// a middleware function with no mount path. This code is executed for every request to the router
router.use(function (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', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (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', function (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(); //
}, function (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', function (req, res, next) {
console.log(req.params.id);
res.render('special');
});
// mount the router on the app
app.use('/', router);
错误处理中间件
错误处理中间件始终采用四个自变量。必须提供四个自变量,以将函数标识为错误处理中间件函数。即使无需使用 next
对象,也必须指定该对象以保持特征符的有效性。否则,next
对象将被解释为常规中间件,从而无法处理错误。
错误处理中间件函数的定义方式与其他中间件函数基本相同,差别在于错误处理函数有四个自变量而不是三个,专门具有特征符 (err, req, res, next)
:
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
有关错误处理中间件的详细信息,请参阅:错误处理。
内置中间件
自 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 的头设置为操作系统上该文件的上次修改日期。有效值包括 true 或 false 。 |
布尔 | true |
maxAge |
设置 Cache-Control 头的 max-age 属性(以毫秒或者 ms 格式中的字符串为单位) | 数字 | 0 |
redirect |
当路径名是目录时重定向到结尾的“/”。 | 布尔 | true |
setHeaders |
用于设置随文件一起提供的 HTTP 头的函数。 | 函数 |
以下示例将使用了 express.static
中间件,并且提供了一个详细的’options’对象(作为示例):
var options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now());
}
}
app.use(express.static('public', options));
对于每个应用程序,可以有多个静态目录:
app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));
有关 serve-static
函数及其选项的更多详细信息,请参阅:serve-static 文档。
第三方中间件
使用第三方中间件向 Express 应用程序添加功能。
安装具有所需功能的 Node.js 模块,然后在应用层或路由器层的应用程序中将其加装入。
以下示例演示如何安装和装入 cookie 解析中间件函数 cookie-parser
。
$ npm install cookie-parser
var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');
// load the cookie-parsing middleware
app.use(cookieParser());
有关 Express 常用的第三方中间件函数的部分列表,请参阅:第三方中间件。