是否可以发送401 Unauthorized AND重定向(带位置)?

时间:2012-01-08 05:24:48

标签: http-headers http-status-code-401 http-redirect

我想发送一个401 Unauthorized并将客户端重定向到某处。但是:

如果我这样做:

header('HTTP/1.1 401 Unauthorized');
header('Location: /');

服务器发送302 Found Location,而不是401 Unauthorized

如果我这样做:

header('Location: /');
header('HTTP/1.1 401 Unauthorized');

浏览器会同时收到401 UnauthorizedLocation,但不会重定向。

(IE 9和Chrome 16表现相同,所以我猜它是正确的)

也许我在滥用HTTP?我希望我的应用程序界面对所有客户端完全相同:文本浏览器,现代浏览器,API调用等.401 +响应文本将告诉API用户什么是什么。重定向对浏览器很有用。

有(好)方式吗?

7 个答案:

答案 0 :(得分:27)

根据定义(请参阅RFC 2616),HTTP 302响应代码 是重定向代码。没有它,可以忽略位置标题。

但是,您可以发送HTTP 401响应并仍然显示输出。您可以在同一请求中编写要在HTTP正文中发送的内容,而不是将用户重定向到错误页面。

答案 1 :(得分:12)

我来这里很晚,但我想我会加两分钱。据我了解,希望表明用户没有正确的授权并提示他们登录.Rudie可以理解地希望返回401 Unauthorized(因为用户需要通过某种机制进行授权,例如记录in),并将它们转发到登录页面 - 但这不是很容易实现,并且大多数库都不支持开箱即用。一种解决方案是在401响应的正文中显示登录页面,如另一个答案中所建议的那样。但是,让我从已建立/最佳实践的角度来看待这一点。

测试案例1:Facebook

在注销时导航到受保护的Facebook页面(我的用户个人资料)会导致404 Not Found响应。 Facebook提供了一个通用的“此页面不可用”页面,其中还包含一个登录表单。有趣。更有趣的是:当我导航到“事件”页面时,我收到了302响应,它转发到登录页面(返回200响应)。所以我猜他们的想法是为我们知道存在的页面返回302,但是为可能存在或不存在的页面提供404(例如,以保护用户的隐私)。

测试案例2:Google收件箱

当我退出时导航到我的收件箱会返回302并将我转发到登录页面,类似于Facebook。我无法弄清楚如何将我的Google+个人资料设为私有,因此没有测试数据...

测试案例3:Amazon.com

当我退出时导航到我的订单历史记录返回302并像以前一样将我转发到登录页面。亚马逊没有“个人资料”页面的概念,因此我无法在此测试。

总结一下这里的测试用例,如果用户需要登录,似乎最好将302 Found发送到登录页面(虽然我认为303 See Other实际上更合适)。这当然只是在真正的人类用户需要以html形式输入用户名和密码的情况下。对于其他类型的身份验证(例如,基本,api密钥等),401 Unauthorized显然是适当的响应。在这种情况下,无需转发到登录页面。

答案 2 :(得分:6)

3xx表示重定向
4xx表示浏览器出错了。

为什么代码按照它们的方式分开是有原因的 - 它们不会混合;)

答案 3 :(得分:4)

除了来自Kolink和David(+ 1)的精美答案之外,我想指出你试图通过返回401并告诉浏览器重定向来改变HTTP协议的语义。这不是HTTP协议的工作方式,如果您确实找到了获得该结果的方法,HTTP客户端将发现您的服务行为是非标准的。

您发送401并允许浏览器处理它,或者您以不同的方式处理情况(例如,作为一个评论者建议,重定向到登录页面或者可能是解释用户无权访问的页面)。 / p>

答案 4 :(得分:3)

这是一个干净的方式:

在401页面上,您可以根据请求中的“接受”标题选择要发送的“视图”。

如果接受为application/json,则可以包含正文:

{"status":401;"message":"Authentication required"}

如果“接受”是text/html,那么您可以加入正文:

<form action="/signin" method="post">
    <!-- bla bla -->
    <input type="hidden" name="redirect" value="[URL ENCODE REQUEST URI]">
</form>

然后你遇到了同样的问题......你成功登录后发出了200 OK还是302 Found? (看我在那里做了什么?)

如果您可以在任何页面上处理身份验证,则只需将表单操作设置为相同的页面URL,但如果要将用户提供的request_uri放在表单操作属性中,则监视XSS

答案 5 :(得分:1)

您可以发送401然后在响应正文中发送window.location ='domain.com'。但是,用户将立即被重定向,而不知道401发生了。

答案 6 :(得分:0)

Web浏览器不是REST客户端。坚持使用Location标头发送状态200,没有正文内容。 30x重定向适用于已移动的页面。不应期望在Web浏览器中重定向其他状态代码/位置标头。

或者,您的Web服务器可能具有可配置的错误页面。您可以将javascript添加到错误页面以重定向。