node.js Web应用框架Express入门指南(3)

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'));
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgpfww.html