在特定路由处理程序提供响应后调用通用路由处理程序

时间:2012-10-09 12:07:51

标签: javascript node.js routes express

我正在尝试向基于Express的服务器添加身份验证。我注意到路由的一些奇怪的行为。

我已将问题提炼为此Express代码:

app.get('/', function (req, res) {
    console.log('this is reached first');
    res.send('Hello');
});

app.get('/', function (req, res) {
    console.log('this is not reached');
});

app.get('*', function (req, res) {
    console.log('this is reached');
});

在请求'/'时,调用第一个处理程序。它提供响应并且不调用next()。因此我很惊讶地看到第3个处理程序('*')也被调用了! 另一个惊喜是传递给第三个处理程序的响应('res')与传递给第一个处理程序的响应不同。 (如果我从第一个处理程序调用next(),那么将调用第二个处理程序,并使用相同的响应对象。)

现在我的真实场景:我想以全局方式处理请求并验证身份验证。但是,某些路由应该仍可供未经身份验证的用户使用。我的解决方案基于Zikes' answer。 我首先选择了“免费”路径。然后我为所有('*')包含了一个路由处理程序。如果用户通过身份验证,则会调用next(),否则调用next(错误)。以下是所有“限制”路线。最后,我自己的错误处理程序使用app.use。它看起来像这样:

app.use(app.router);
app.use(function(err, req, res, next) {
    console.log('An error occurred: ' + err);
    res.send(401, 'Unauthorized');
});

app.get('/', function (req, res) {
    res.send('Hello all');
});

app.all('*', function (req, res, next) {
    if (req.user) {
        next(); // authorized
    } else {
        next(new Error('401')); // unauthorized
    }
});

app.get('/members', function (req, res) {
    res.send('Hello member');
});

这很有效,阻止访问'/ members'。但是,它有错误:即使访问非限制路径('/'),也会发生身份验证检查和错误处理。发送预期的响应后,错误处理程序尝试发送401错误响应。后者不会被发送,但代码不应该运行。

此外,此机制的一个副作用是未经身份验证的用户对不存在的页面会收到401错误。在某些情况下,我可能想要返回404。但现在我只是推动它......

我有两个问题:

  1. 这种行为是个错误吗?是否应调用通用处理程序而不调用它?
  2. 连接许多但不是所有路线的好方法是什么,而不必单独标记它们?

3 个答案:

答案 0 :(得分:2)

对于第一个问题,我的猜测是浏览器正在发送多个请求。

例如,当您浏览http://localhost:3000/ Chrome时,Chrome也会请求http://localhost:3000/favicon.ico

您可以使用以下内容打印正在捕获的请求:

app.get('*', function (req, res) {
    console.log('this is reached');
    console.log('url ' + req.url );
});

答案 1 :(得分:1)

app.get('/', function(req, res, next) {
    console.log('this is reached first.');
    next();
}, function (req, res) {
    console.log('this is reached last.');
    res.send('Hello all');
});

我通常会像这样构建它:

var auth = require('../modules/authenticate');

app.get('/', auth.requireLogin, routes.index.get);
app.delete('/items/:id', auth.requireLogin, auth.permission.item.delete, routes.item.delete);

答案 2 :(得分:1)

首先,你在回家时可能有两个请求(favicon.ico)。使用app.use(express.logger('dev'))记录请求。此外,您可以尝试阻止该路径:

app.use('/favicon.ico', function(req, res) {
  console.log('FAVICON')
  res.send(404)
}

其次,您想要处理错误。发送错误的好方法:

var err = new Error('this is my error message.')
err.status = 404 // You want to send a "Not Found" page
next(err)

app.use(function(err, req, res, next) {
  var status = err.status
  if (status === 404) res.send(404, 'Page not found.');
  else res.send(500, 'Something went wrong.');
})

所有处理的错误都应该具有状态。