Express的中间件和路由中间件为路径映射及控制提供了更方便和强大的功能,本文将提供这些内容的使用指引。
中间件(Middleware)
中间件可以通过Connect传入express.createServer(),就像正常的连接服务器一样,比如:
var express = require('express'); var app = express.createServer( express.logger(), express.bodyParser() );
另外,在configure()函数块中利用use()函数增加中间件,也是一种很好的方式。
app.use(express.logger({ format: ':method :uri' }));
通常连接中间件可以通过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());
路由中间件(Route Middleware)
这里路径映射也可以理解为路由的意思,路由通过传入一个或多个附加的回调函数(或数组)到方法中,从而可以利用特定路由的中间件。该功能对限制访问以及加载路由使用的数据非常有用。
通常情况下异步数据的查询看起来像下面的样子,这里我们使用: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 of csser.com ' + user.name); }); });
为了保持代码整洁并且提高可读性,我们可以在中间件内部应用该逻辑。正如你所看到的,将逻辑抽象到中间件里让我们达到一定程度的复用,同时代码更干净。
function loadUser(req, res, next) { // 这里提供假数据,你可以从数据库中获取真实用户信息 var user = users[req.params.id]; if (user) { req.user = user; next(); } else { next(new Error('不存在的用户 ' + req.params.id)); } } app.get('/user/:id', loadUser, function(req, res){ res.send('正在查看用户 ' + req.user.name); });
一回注:看到了吗?上面的路径映射的回调函数参数是可以支持多个的。
多重路由中间件可以被按照顺序来执行,从而可以实现更复杂的逻辑,比如限制访问某个用户的访问权限,下面的代码将只允许认证用户才可以编辑其帐号信息。
function andRestrictToSelf(req, res, next) { req.authenticatedUser.id == req.user.id ? next() : next(new Error('无权限')); } app.get('/user/:id/edit', loadUser, andRestrictToSelf, function(req, res){ res.send('开始编辑用户 ' + req.user.name); });
请记住中间件是简单的函数,我们还能定义返回中间件的函数,从而可以创建一个更有表现力和更易用的如下方案:
function andRestrictTo(role) { return function(req, res, next) { req.authenticatedUser.role == role ? next() : next(new Error('无权限')); } } app.del('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){ res.send('已删除用户 ' + req.user.name); });
一回注:app.del的第三个参数之所以可以这样写,是因为其返回的是一个函数,而该函数可以访问’admin’的值,这里涉及到闭包的概念,如有疑问请在CSSer.com查找闭包相关文章。
通常使用的中间件的“栈”可以被作为数组(递归应用)传入,如此可以被混合并能匹配更复杂的功能。
var a = [middleware1, middleware2] , b = [middleware3, middleware4] , all = [a, b]; app.get('/foo', a, function(){}); app.get('/bar', a, function(){}); app.get('/', a, middleware3, middleware4, function(){}); app.get('/', a, b, function(){}); app.get('/', all, function(){});
可以去express源码仓库查看完整的路由中间件示例。