将Express.js 4的res.status(401)链接到重定向

bro*_*ock 14 redirect node.js http-status-code-401 express

如果请求用户未经过身份验证,我想发送一个401的响应代码,但我还想在请求是HTML请求时重定向.我一直发现Express 4不允许这样:

res.status(401).redirect('/login')
Run Code Online (Sandbox Code Playgroud)

有谁知道处理这个的方法?这可能不是Express的限制,因为我要求基本上传递两个标题,但我不明白为什么会出现这种情况.我应该能够传递"未经过身份验证"的响应并将用户一次性重定向.

Jas*_*ust 19

发送回新位置标题的方法存在一些细微差别.

redirect:

app.get('/foobar', function (req, res) {
  res.redirect(401, '/foo');
});
// Responds with
HTTP/1.1 401 Unauthorized
X-Powered-By: Express
Location: /foo
Vary: Accept
Content-Type: text/plain; charset=utf-8
Content-Length: 33
Date: Tue, 07 Apr 2015 01:25:17 GMT
Connection: keep-alive

Unauthorized. Redirecting to /foo
Run Code Online (Sandbox Code Playgroud)

statuslocation:

app.get('/foobar', function (req, res) {
  res.status(401).location('/foo').end();
});
// Responds with
HTTP/1.1 401 Unauthorized
X-Powered-By: Express
Location: /foo
Date: Tue, 07 Apr 2015 01:30:45 GMT
Connection: keep-alive
Transfer-Encoding: chunked
Run Code Online (Sandbox Code Playgroud)

使用原始(不正确)方法redirect:

app.get('/foobar', function (req, res) {
  res.status(401).redirect('/foo')();
});
// Responds with 
HTTP/1.1 302 Moved Temporarily
X-Powered-By: Express
Location: /foo
Vary: Accept
Content-Type: text/plain; charset=utf-8
Content-Length: 38
Date: Tue, 07 Apr 2015 01:26:38 GMT
Connection: keep-alive

Moved Temporarily. Redirecting to /foo
Run Code Online (Sandbox Code Playgroud)

所以它看起来redirect会放弃任何以前的状态代码并发送默认值(除非在方法调用中指定).由于在Express中使用了中间件,这是有道理的.如果您有一些全局中间件对所有请求进行预检查(例如检查正确的接受标头等),他们就不会知道重定向请求.但是,身份验证中间件会因此而知道覆盖任何先前的设置以正确设置它们.

更新:如下面的评论中所述,尽管Express可以发送带有Location头的4XX状态代码,但这并不意味着它是一个可接受的响应,请求客户端根据规范理解.事实上,除非状态代码是3XX值,否则大多数会忽略Location标头.

  • @JustinMaat同意这个的整体用法是不正确的.401应该被发送回请求者,让他们知道他们应该使用通过[`WWW-Authenticate`](http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error)标题指定的正确认证方法再次请求.这通常是令牌或基本身份验证.我的回答是表明Express*可以*做到但不是这样做是正确的.更新我的答案以反映这一点. (2认同)

lxe*_*lxe 7

您当然可以Location: /login在401页面旁边发送标题,但是,这是不明智的,大多数浏览器都不会遵循它,如rfc2616.

解决此问题的一种方法是<meta http-equiv="refresh" content="0; url=/login">与您的401页面一起提供服务:

res.set('Content-Type', 'text/html');
res.status(401).send('<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=/login"></head></html>`);
Run Code Online (Sandbox Code Playgroud)

  • 很抱歉恢复这个旧主题,但您的 `.send()` 方法中似乎有一个结束反引号而不是单引号。使用了您的好主意,但我不知道为什么会出错:) 谢谢! (2认同)