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

时间:2015-04-07 00:19:37

标签: node.js redirect express http-status-code-401

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

res.status(401).redirect('/login')

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

3 个答案:

答案 0 :(得分:18)

发送回新位置标题的方法存在一些微妙的差异。

使用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

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

使用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

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

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

答案 1 :(得分:6)

您当然可以在401页面旁边发送Location: /login标题,但这是不明智的,大多数浏览器都不会按照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>`);

答案 2 :(得分:0)

我遇到了同样的问题,并决定使用会议来处理这种工作。

我不想有一个中间观点...

使用以下代码,我可以重定向到主页,该主页将显示401个未经授权的代码。

app.get('patternForbiddenRoute', (req, res, next) => {
       // previousCode
       if (notForbidden === true) {
           return res.render("a_view");
       }

       req.session.httpCode = 401;

       res.redirect('patternHomeRoute');
});

app.get('patternHomeRoute', (req, res, next) => {
       res.render("my_home_view", {}, (error, html) => {
            // ... handle error code ...

            const httpCode = req.session.httpCode;
            if (httpCode !== undefined) {
                delete req.session.httpCode;
                res.status(httpCode);
            }

            res.send(html);
       }));
});