什么是中间件?
中间件是一种功能的封装方式,具体来说就是封装在程序中处理HTTP 请求的功能。
从实战上讲,例如之前定义的500页面。
app.use(function(err, req, res , next){
console.error(err.stack);
res.type('text/plain');
res.status(500);
res.render('500');
});
中间件只是一个有4个参数的函数:
err : 用来做错误处理
req / res : 用于请求和响应
next : 指向玩中间件后继续后续处理
如何理解中间件了?
中间件是在管道中执行的。你可以想象一个送水的真实管道。水从一端泵入,然后在到达目的地之前还会经过各种仪表和阀门。这个比喻中很重要的一部分是顺序问题,你把压力表放在阀门之前和之后的效果是不同的。同样,如果你有个向水中注入什么东西的阀门,这个阀门“下游”的所有东西都会含有这个新添加的原料。在Express程序中,通过调用app.use 向管道中插入中间件。
从中间件和路由的区别来理解会更加直观,路由的功能是根据请求路径和请求方法来处理特定的请求,而中间件则作用于全部请求。这个特性就决定了中间件可以预先加工所有请求再转交给特定的路由来进行处理。
如何使用中间件?
在Express 4.0 之前,中间件与路由的关系比较复杂。在中间件中必须要把路由器连进来。
在Express 4.0 中,中间件和路由处理器是按它们的连入顺序调用的,顺序更清晰。也就是书写代码的顺序来处理他们之间的关系,这样的结构就和作者所具的管道非常像。
app.use(function(req, res, next){
console.log('processing request for "' + req.url + '"....');
next();
});
app.use(function(req, res, next){
console.log('terminating request');
res.send('thanks for playing!');
// 注意,我们没有调用next()……这样请求处理就终止了
});
app.use(function(req, res, next){
console.log('whoops, i\'ll never get called!');
});
这里有三个中间件。第一个只是在将请求传给下一个中间件之前记录一条消息。然后下一个中间件会真正地处理请求。注意,如果我们忽略了res.send,则不会有响应返回到客户端,最终会导致客户端超时。最后一个中间件永远也不会执行,因为所有请求都在前一个中间件中终止了。
var app = require('express')();
app.use(function(req, res, next){
console.log('\n\nALLWAYS');
next();
});
app.get('/a', function(req, res){
console.log('/a: 路由终止');
res.send('a');
});
app.get('/a', function(req, res){
console.log('/a: 永远不会调用');
});
app.get('/b', function(req, res, next){
console.log('/b: 路由未终止');
next();
});
app.use(function(req, res, next){
console.log('SOMETIMES');
next();
});
app.get('/b', function(req, res, next){
console.log('/b (part 2): 抛出错误' );
throw new Error('b 失败');
});
app.use('/b', function(err, req, res, next){
console.log('/b 检测到错误并传递');
next(err);
});
app.get('/c', function(err, req){
console.log('/c: 抛出错误');
throw new Error('c 失败');
});
app.use('/c', function(err, req, res, next){
console.log('/c: 检测到错误但不传递');
next();
});
app.use(function(err, req, res, next){
console.log(' 检测到未处理的错误: ' + err.message);
res.send('500 - 服务器错误');
});
app.use(function(req, res){
console.log(' 未处理的路由');
res.send('404 - 未找到');
});
app.listen(3000, function(){
console.log(' 监听端口3000');
});
中间件与入口程序分离
中间件必须是一个函数。
你会注意到express.static 是一个函数,但我们真的会调用它,所以它必须返回另一个函数。看一下:
app.use(express.static); // 这个不会像我们期望的那样工作
console.log(express.static()); // 将会输出"function",表明express.static 是一个会返回函数的函数
通过node模块分离中间件
创建lib/cartValidation.js
module.exports = {
checkWaivers: function(req, res, next){
var cart = req.session.cart;
if(!cart) return next();
if(cart.some(function(i){ return i.product.requiresWaiver; })){
if(!cart.warnings) cart.warnings = [];
cart.warnings.push('One or more of your selected ' +
'tours requires a waiver.');
}
next();
},
checkGuestCounts: function(req, res, next){
var cart = req.session.cart;
if(!cart) return next();
if(cart.some(function(item){ return item.guests >
item.product.maximumGuests; })){
if(!cart.errors) cart.errors = [];
cart.errors.push('One or more of your selected tours ' +
'cannot accommodate the number of guests you ' +
'have selected.');
}
next();
}
}
引入中间件
var cartValidation = require('./lib/cartValidation.js');
app.use(cartValidation.checkWaivers);
app.use(cartValidation.checkGuestCounts);
10.1 常用中间件在前面的例子中,我们的中间件会用语句return next()提前终止。Express不期望中间件返回值(并且它不会用返回值做任何事情),所以这只是缩短了的next(); return;。
之前许多常用的中间件都放置在Connect中。express4.0后Connect独立出来了。也就是说安装express后需要在安装Connect
npm install--save connect
引入
var connect = require(connect);