var app = express.createServer(
express.logger()
, express.bodyParser()
);
另外,在 configure() 块内 —— 这个渐进式的宫殿(译注:笑^^,in a progressive manner),我们还可以方便地使用 use() 来添加中间件。
复制代码 代码如下:
app.use(express.logger({ format: ':method :url' }));
通常,使用 connect 中间件你可能会用到 require('connect'),像这样:
复制代码 代码如下:
var connect = require('connect');
app.use(connect.logger());
app.use(connect.bodyParser());
这在某种程度上来说有点不爽,所以 express 重导出(re-exports)了这些中间件属性,尽管他们是一样的:
复制代码 代码如下:
app.use(express.logger());
app.use(express.bodyParser());
中间件的顺序非常重要,当 Connect 收到一个请求,我们传到 createServer() 或者 use() 执行的第一个中间件将附带三个参数,request、response,以及一个回调函数(通常是 next)。当 next() 被调用,将轮到第二个中间件,依此类推。之所以说这是值得注意的,是因为很多中间件彼此依赖,例如 methodOverride() 查询 req.body 方法来检测 HTTP 方法重载,另一方面 bodyParser() 解析请求内容并将其于寄存于 req.body。另一个例子是 cookie 解析和 session 支持,我们必须先 use() cookieParser() 紧接着 session()。
很多 Express 应用都包含这样的一行 app.use(app.router),这看起来可能有点奇怪,其实它仅仅是一个包含所有定义路由规则,并执行基于现有 URL 请求和 HTTP 方法路由查找的一个中间件功能。Express 允许你决定其位置(to position),不过默认情况下它被放置于底部。通过改变路由的位置,我们可以改变中间件的优先级,譬如我们想把错误报告做为最后的中间件,以便任何传给 next() 的异常都可以通过它来处理;又或者我们希望静态文件服务优先级更低,以允许我们的路由可以监听单个静态文件请求的下载次数,等等。这看起来差不多是这样的:
复制代码 代码如下:
app.use(express.logger(...));
app.use(express.bodyParser(...));
app.use(express.cookieParser(...));
app.use(express.session(...));
app.use(app.router);
app.use(express.static(...));
app.use(express.errorHandler(...));
首先我们添加 logger(),它可能包含 node 的 req.end() 方法,提供我们响应时间的数据。接下来请求的内容将会被解析(如果有数据的话),紧接着的是 cookie 解析和 session 支持,同时 req.session 将会在触发 app.router 中的路由时被定义,这时我们并不调用 next(),因此 static() 中间件将不会知道这个请求,如若已经定义了如下一个路由,我们则可以记录各种状态、拒绝下载和消耗下载点数等。
复制代码 代码如下:
var downloads = {};
app.use(app.router);
app.use(express.static(__dirname + '/public'));
app.get('/*', function(req, res, next){
var file = req.params[0];
downloads[file] = downloads[file] || 0;
downloads[file]++;
next();
});
十、路由中间件
路由可以利用路由器中间件,传递一个以上的回调函数(或者数组)到其方法中。这个特性非常有利于限制访问、通过路由下载数据,等等。
通常异步数据检索看起来可能像下例,我们使用 :id 参数,尝试加载一个用户:
复制代码 代码如下:
app.get('/user/:id', function(req, res, next){
loadUser(req.params.id, function(err, user){
if (err) return next(err);
res.send('Viewing user ' + user.name);
});
});
为保证 DRY 原则和提升可读,我们可以把这个逻辑应用于一个中间件内。如下所示,抽象这个逻辑到中间件内将允许你重用它,同时保证了我们路由的简洁。
复制代码 代码如下:
function loadUser(req, res, next) {
// You would fetch your user from the db
var user = users[req.params.id];
if (user) {
req.user = user;
next();
} else {
next(new Error('Failed to load user ' + req.params.id));
}
}
app.get('/user/:id', loadUser, function(req, res){
res.send('Viewing user ' + req.user.name);
});
多重路由可以,并按顺序应用到更深一层的逻辑,如限制一个用户账号的访问。下面的例子只允许通过鉴定的用户才可以编辑他(她)的账号。
复制代码 代码如下:
function andRestrictToSelf(req, res, next) {
req.authenticatedUser.id == req.user.id
? next()
: next(new Error('Unauthorized'));
}