- Published on
Express Middleware
- Authors
- Name
- Deng Hua
目录
什么是中间件
一个 web 服务器可以被看作是一个接收请求(request
)并输出响应(response
)的函数。Middlewares 是在接收请求后执行的函数,然后产生一个输出,这个输出可以是最终输出,也可以被下一个中间件使用(作为下一个中间件的输入),直到循环完成。
这意味着我们可以有多个中间件,并且它们将按照声明的顺序执行。下面的 middleware A 在 middleware B 之前执行,在 middleware B 之前执行 middleware C。我们可以从一个中间件传递变量到另一个中间件。
中间件的简单使用
要设置中间件,您可以为要添加的每个中间件层调用 app.use()
。中间件可以对所有路径通用,也可以仅在服务器的特定路由上触发。下面是中间件声明的示例。
const express = require('express');
const app = express();
const 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 只是显示消息,然后通过调用 next()
函数将请求传递到堆栈中的下一个中间件函数。
中间件装载顺序遵循先后顺序,即首先装入的中间件函数首先被执行。
如果在根路径('/')的路由之后装入 myLogger
,那么请求永远都不会到达该函数,应用程序也不会显示LOGGED
,因为根路径的路由处理程序终止了请求/响应循环。
// ...
const myLogger = function (req, res, next) {
console.log('LOGGED');
next();
};
app.get('/', function (req, res) {
app.use(myLogger); // myLogger middleware it will never be called.
res.send('Hello World!');
});
// ...
中间件函数类型
Express 应用程序可以使用以下类型的中间件:
- 应用层中间件
- 路由器层中间件
- 错误处理中间件
- 内置中间件
- 第三方中间件
应用层中间件
我们可以编写一个中间件函数,传入 app.use
来记录一个请求的请求方法,如下:
const express = require('express')
const app = express()
app.use((req, res, next) => {
console.log(req.method);
next();
});
app.get('/', (req, res) => {
res.json();
})
app.listen(3001);
然后,当我们向 /
路由发出 GET
请求时,应用程序会打印GET
。
如果没有指定挂在何种路由上,则应用程序每次收到请求时都会执行该函数:
app.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
此示例为一个挂载在 /user/:id
路由中的中间件函数。在 /user/:id
路由中将为任何类型的 HTTP 请求执行此函数:
const express = require('express')
const app = express()
app.use('/user/:id', function (req, res, next) {
console.log('Request params id:', req.params.id);
next();
});
app.listen(3001);
访问 localhost:3001/user/3 ,将打印: Request params id: 3
也可以指定具体的HTTP请求方法:
// ...
app.get('/user/:id', function (req, res, next) {
res.send('USER');
});
// ...
或者定义多个中间件函数:
app.use('/user/:id', function (req, res, next) {
console.log('Request params id:', req.params.id); // Request Type: 3
next();
},function (req, res, next) {
console.log('Request method:', req.method); // Request method: GET
});
路由器层中间件
路由器级中间件的工作方式与应用程序级中间件相同,但它们绑定到 express.Router()
实例而不是 express 实例。使用 router.use()
和 router.METHOD()
函数装入路由器层中间件。
例如:
const express = require('express')
const app = express()
const router = express.Router();
router.use((req, res, next) => { // 使用 router.use 或者 router.get
req.requestTime = new Date();
next();
})
router.get('/', (req, res, next) => {
res.json(req.requestTime);
})
app.use('/', router);
app.listen(3001);
然后,当我们向 /
路由发出请求时,我们会返回时间戳作为输出。
链接中间件和跳过路由的工作方式与应用程序级中间件相同。例如:
const express = require('express')
const app = express()
const router = express.Router();
router.use(
(req, res, next) => {
console.log('middleware 1 called');
next();
},
(req, res, next) => {
console.log('middleware 2 called');
next();
}
)
router.get('/', (req, res, next) => {
res.json();
})
app.use('/', router);
app.listen(3001);
然后我们从每个路由中间件的 console.log
输出中看到:
middleware 1 called
middleware 2 called
如果我们注释第一个中间件的next()
:
router.use(
(req, res, next) => {
console.log('middleware 1 called');
// next();
},
(req, res, next) => {
console.log('middleware 2 called');
next();
}
)
则只会打印
middleware 1 called
next('route')
来跳转路由,如下:
使用 const express = require('express')
const app = express()
const router = express.Router();
// 挂载一个路由中间件,匹配GET请求,路径为"/:id"
router.get('/:id',
(req, res, next) => {
console.log('First middleware')
if (req.params.id === '0') { // 匹配 '/0',命中匹配,跳转下一个路由器
next('route');
} else { // 否则执行本路由器的下一个中间件
next();
}
},
(req, res, next) => {
res.send('Second middleware');
}
)
router.get('/:id', (req, res, next) => { // 只有命中 '/0' 路径才会执行此中间件,响应字符串"Second middleware",结束此次请求
res.send(req.params.id);
})
app.use('/', router);
app.listen(3001);
然后当我们向 '/0' 发出请求时,我们得到 0
。否则会输出 ‘Second Middleware’ 。
错误处理中间件
错误处理中间件始终采用四个自变量。必须提供四个自变量,以将函数标识为错误处理中间件函数。即使无需使用 next 对象,也必须指定该对象以保持特征符的有效性。否则,next 对象将被解释为常规中间件,从而无法处理错误。
错误处理中间件函数的定义方式与其他中间件函数基本相同,差别在于错误处理函数有四个自变量而不是三个,专门具有特征符 (err, req, res, next)
:
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
内置中间件
express.static(root, [options])
Express 中唯一内置的中间件函数是 express.static。此函数基于 serve-static,负责提供 Express 应用程序的静态资源。
root 自变量指定从其中提供静态资源的根目录。
以下示例将使用了 express.static 中间件,并且提供了一个详细的’options’对象(示例):
const 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'));
第三方中间件
使用第三方中间件向 Express 应用程序添加功能。
安装具有所需功能的 Node.js 模块,然后在应用层或路由器层的应用程序中将其加装入。
以下示例演示如何安装和装入 cookie 解析中间件函数 cookie-parser。
$ npm install cookie-parser
const express = require('express');
const app = express();
const cookieParser = require('cookie-parser');
app.use(cookieParser());
有关 Express 常用的第三方中间件函数的部分列表,请参阅:第三方中间件。