2012-10-09 74 views
2

我试图将身份验证添加到基于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()。因此,我很惊讶地发现第三个处理程序('*')也被称为! 另一个惊喜是传递给第三个处理程序的响应('res')与传递给第一个处理程序的响应不同。 (如果我要从第一个处理程序调用next(),那么第二个处理程序将被调用,并且具有相同的响应对象。)

现在对于我的真实场景:我想处理请求并验证全局身份验证方式。但是,有些路由应该保持可用于未经过身份验证的用户。我基于Zikes' answer的解决方案。 我首先路由了“自由”路径。然后我包含了一个全部路由处理程序('*')。如果用户通过验证,它会调用next(),否则调用next(err)。以下是所有“限制”路线。最后,我使用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'); 
}); 

这工作得很好,阻止访问'/成员'。但是,它存在一些错误:即使在访问非限制路径('/')时也会发生身份验证检查和错误处理。发送预期响应之后,错误处理程序将尝试发送401错误响应。后者不会被发送,但代码不应该运行。

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

我还挺有2个问题:

  1. 这种行为是错误?一般处理程序是否应该在未被调用的情况下调用?
  2. 什么将是一个很好的解决方案,以钩住许多但不是所有的路线,而不必单独标记它们?

回答

2

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

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

可以打印正赶上了这样的要求:

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

你也可以使用'app.use(express.logger('dev'))'这是更好打印出来的信息 –

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); 
+0

关于第一部分,你的代码确实更优雅,但这不是问题。我的代码示例可能是不正确的,但它只是用来表示一个观点。无论如何,强调的是'get *'声明本应该不被调用(在我看来)。 关于第二部分,我不太确定'routes.index.get'是什么意思。 – oferei

+0

routes.index是处理所有请求的模块。 – chovy

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

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

相关问题