中间件函数在应用的request--reponse周期中,能够使用request对象(req)、response对象(res)和next函数(next)。能够实现如下功能
- 执行逻辑代码;
- 更改request对象和response对象;
- 结束request--reponse周期;
- 调用栈中的下一个中间件。
tips: 如果当前的中间件函数没有结束request--reponse周期,则必须调用next(),将控制权交给下一个中间件函数,否则请求将被挂起。 执行逻辑代码的中间件的顺序需要在路由handler之前,否则不会执行其代码,因为路由handler会结束掉这个request-response cycle
Express的应用可以使用以下类型的中间件: - 应用级别中间件
- 路由级别中间件
- 错误处理中间件
- 内置中间件
- 第三方中间件
可以使用可选的挂载路径(不配置挂载路径的话默认挂载在根目录下/) 加载应用级别和路由级别的中间件 。也可以加载一系列的中间件函数,这样会在挂载点创建一个中间件系统的子堆栈。
1. 应用级别中间件
将应用级别的中间件绑定到Express实例--app上,使用app.use()
和app.METHOD(此METHOD指get、post等方法)
tips: 从一个路由到另一个路由(路由使用app.METHOD或router.METHOD定义的),使用next('route')
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) {
// send a regular response
res.send('regular')
})
// handler for the /user/:id path, which sends a special response
app.get('/user/:id', function (req, res, next) {
res.send('special')
})
2. 路由级别中间件
同应用级别的中间件用法相同,不同之处的是它是绑定在router实例(express.Router())上的
tips: 同样也可以使用next('route') 从一个路由到另一个路由(另一个路由使用router.METHOD定义的)
3. 错误处理中间件
与其他中间件函数的定义基本相同,不同之处在于错误处理函数多了一个变量:err,即它有4个变量:err, req, res, next
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
tips: next() 传入的参数除了字符串'route'外,其他参数会认为出错,交由错误处理函数处理。若未显式定义错误处理函数,则函数集的末尾有express隐式包含的默认错误处理程序。
4. 内置中间件
express.static()、express.json()、express.urlencoded()等
5. 第三方中间件
如操作cookie的cookie-parser,
读取解析的cookie用req.cookies(读取被签名的cookie用req.signedCookies),读取cookie字符串用express的req.headers.cookie;
设置cookie用express的res.cookie(key, value)或res.header('Set-Cookie', 'key=value');
var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');
app.use('cookieParser ');
app.get('/', function(req, res, next){
console.log(req.cookies); // 解析过的object的形式--{ k1: 'v1', k2: 'v2' }。引入了cookie-parser方可使用
console.log(req.headers.cookie);// string的形式--k1=v1; k2=v2。express原生可以用
res.cookie('key3', 'val3'); // 设置cookie,express原生可以用
res.send('cookie example');
})
tips:使用session可以用express-session中间件,默认是存储在内存中,server重启后会丢失,不适用于生产环境。可以通过设置store参数 将session内容存储在数据库中。
tips:关于安全问题的两点:
- app.disable('x-powered-by'); reponse中不会返回X-Powered-By字段(如果不做设置会返回server的类型,如X-Powered-By: Express,可能导致针对性的攻击);
- 使用session时,将cookie中sessionid的key设置为通用的字符串如sessionID(不设置的话sessionid默认的key为connect.sid),同上一条的原因一样,防止黑客针对你的后台类型进行针对性攻击。
app.use(session({
name : 'sessionId',
resave:false,
saveUninitialized: false
}));