应该使用啥 http 状态代码来告诉客户端会话已超时?

Posted

技术标签:

【中文标题】应该使用啥 http 状态代码来告诉客户端会话已超时?【英文标题】:What http status code is supposed to be used to tell the client the session has timed out?应该使用什么 http 状态代码来告诉客户端会话已超时? 【发布时间】:2010-12-11 19:53:42 【问题描述】:

在网页中,它使用 YUI 连接管理器/数据源向服务器发送 AJAX 请求,如果会话(包含有关用户是否已通过身份验证的信息)已经超时,那些只能是被认证的用户查看应该返回一个 http 状态码,告诉客户端会话已经超时,然后客户端要么简单地将他重定向到登录页面,要么询问他是否要延长会话。

我的问题是,在这种情况下,什么 http 状态码最适合告诉客户端会话已超时?

List of HTTP status codes from wiki

【问题讨论】:

您是否要警告用户会话即将到期,以便用户可以做一些事情来更新它?如果是这种情况,它必须由 javascript 中的计时器处理,该计时器在服务器上的会话超时之前关闭。当服务器发送状态码时,它已经过期了。如果您将他们自动重定向到另一个页面(如果他们让页面空闲),则还需要一个计时器。 为什么,当然是 418!又矮又粗…… Vaadin 使用 410 Gone,但由于它可以被浏览器缓存,我不推荐它 【参考方案1】:

我能建议的最好的是带有 WWW-Authenticate 标头的 HTTP 401 状态代码。

403 请求的问题是RFC 2616 声明“授权无济于事,请求不应重复”。 (即无论您是否经过身份验证,您永远都无法访问该资源)。

401 请求的问题在于它声明它们“必须包含 WWW-Authenticate 标头字段”。作为someone has noted,在 WWW-Authenticate 标头中使用自定义值似乎不违反规范。

我在 RFC 2617 中看不到任何原因,为什么 HTTP 401 状态与像这样的自定义 WWW-Authenticate 标头结合使用是不行的:

WWW-Authenticate: MyAuthScheme realm="http://example.com"

oAuth spec 实际上似乎就是这样做的,因为他们建议这样做(尽管我认为他们对 RFC 有一个奇怪的解释):

WWW-Authenticate: OAuth realm="http://server.example.com/"

这似乎没有受到 RFC 的特别批准,但我实际上看不出它被它禁止(它似乎与任何必须或不得、应该或不应条件相冲突)。

我希望有一个更具体的 HTTP 状态代码用于超时和 CSRF 令牌无效等事情,这样会更清楚。

【讨论】:

【参考方案2】:

我会推荐一个 HTTP 401。

而 403 基本上是说,“你不被允许,走开,不要回来”,而 401 说,“我们不知道你是否被允许,因为你没有带上你的ID。去拿它再试一次。”

比较Wikipedia's definitions:

HTTP 403 - 请求是合法请求,但服务器拒绝响应。

HTTP 401 - 类似于 403 Forbidden,但专门用于身份验证可能但失败或尚未提供的情况。

【讨论】:

401 用于 HTTP 身份验证。 RFC 2616 说response MUST include a WWW-Authenticate header field。因此,在没有 WWW-Authenticate 标头字段的情况下发送该代码是错误【参考方案3】:

419 怎么样 - 它不是标准的,但 description on Wikipedia 似乎很合适:

419 验证超时

不是 HTTP 标准的一部分,419 Authentication Timeout 表示 先前有效的身份验证已过期。它被用作 401 Unauthorized 的替代品,以区别于 否则,经过身份验证的客户端被拒绝访问特定服务器 资源。

【讨论】:

知道这来自哪里(***除外)?如果它不在官方 RFC 中,是谁定义的? 它似乎也从那个 wiki 页面中删除了 这不是规范的一部分,在 Java HttpServletResponse@John 中也没有,如果您知道任何其他可靠的来源,最好参考它。 我似乎只在 php Laravel 中使用 这段代码是特定于 Laravel 框架的。它不是由 RFC 支持的官方 HTTP 响应代码。【参考方案4】:

我相信适当的代码将是 403/Forbidden。没有任何与会话直接相关的内容。

【讨论】:

这绝对是正确的答案。由于会话已经超时,请求被禁止,所以这是最好的选择。 403 告诉客户端(基本上)“除非您修改您的请求,否则不要再这样做了”,但如果会话已建立,则无需修改。此外,在大多数情况下,您无法对(当前)重新建立会话的请求执行任何操作。 没错!我认为 401 会更好,但它需要 HTTP 身份验证。我认为这需要一个类似于 401+303(显然是 704)的新状态,这意味着“未授权,请参阅其他以获得授权”。除了在语义上更正确之外,它还可以是蹦床重定向的 HTTP 解决方案,基本上是“去这里,然后当你回来我们会再试一次”,这样登录页面就可以不知道目的地。 我不能同意这一点,RFC 2616 明确指出客户端“不应重复”导致 403 响应的请求并且“授权无济于事”。 authorization will not help - 我认为这意味着 HTTP 身份验证 无济于事。哪个是对的。发送 Authorization 标头不会改变任何内容。 401 和 403 都不理想,但我认为 403 比 401更好。401 对于会话超时错误,因为 RFC 2616 明确声明 client MAY repeat the request with a suitable Authorization header field。但是,在这种情况下,客户端不应该重复请求(至少在没有中间步骤的情况下是这样)。不幸的是,我们不能用状态码来传达后面的部分。【参考方案5】:

当您发布链接时,我在该链接中找到了这个 HTTP 状态代码 440。您可以使用 440 HTTP 状态码表示会话已过期。

440 登录超时

 The client's session has expired and must log in again.

401 Unauthorized we can use when, user login credential is wrong.或标头中传递的身份验证令牌无效。

403 Forbidden 当用户对请求的资源没有特定权限时,我们可以使用它。

所以我认为我们应该使用440 Login Time-out

【讨论】:

此代码特定于 Microsoft IIS 服务器。它不是由 RFC 支持的官方 HTTP 响应代码。 同意@8bitjunkie【参考方案6】:

根据上面由 Bobo 提供的Http Status Codes 的***链接:

440 Login Timeout (Microsoft)

    A Microsoft extension. Indicates that your session has expired.

【讨论】:

请注意 apache 可能会将返回状态转换为 500,就像我的一样 - ***.com/questions/17735514/… 我喜欢这个适用于 ASP.NET 环境的解决方案。 此代码特定于 Microsoft IIS 服务器。它不是由 RFC 支持的官方 HTTP 响应代码。【参考方案7】:

事实上,会话超时没有标准的 HTTP 状态代码。会话是在应用层实现的,而不是 HTTP 传输层。

微软一直在使用一个自定义状态码来表示会话超时:599,或者干脆在 5xx 范围内编造自己的状态码。

来自状态码 Wiki:

599 网络连接超时错误(未知) 此状态代码未在任何 RFC 中指定,但 Microsoft Corp. HTTP 代理使用该状态代码向代理前面的客户端发送代理后面的网络连接超时信号。

我使用自定义状态码 599 表示会话超时,然后在 AJAX 响应中检查它。

【讨论】:

网络连接超时与会话超时有很大不同。如果您要使用 Microsoft 扩展中的代码,为什么不使用 440 Login Timeout (Microsoft) 按照 Faisal Mq's answer 关于 599 的***页面是错误的,并且没有引用。它显然曾经说过微软代理在网络超时时引发 599,但我也找不到任何证据。【参考方案8】:

从技术上讲,接受的答案当然是正确的:如果您已经确定您将失败请求,并且您正在询问返回哪个失败代码,那么 HTTP 401“未经授权(未经身份验证)”是适当的一个,以便提示重新认证。

但首先,问问你自己:你应该让请求失败吗?

假设用户可能只是在访问您网站的公共页面,在这种情况下,您将用“未经授权!”来打他们的脸。消息,并要求他们重新进行身份验证,以便查看他们通常无需身份验证即可看到的页面。这不酷。

我的建议是忽略会话令牌未知的事实,并简单地继续生成新会话令牌并为其创建新会话。会话的初始状态当然是“尚未验证”,因此如果用户尝试访问非公共页面,则该页面将确保他们收到 HTTP 401“未授权(未验证) "并且必须进行身份验证。但如果用户登陆公共页面,他们不会注意到任何不同。

【讨论】:

【参考方案9】:

我会使用 302 重定向响应,其中“Location”标头指向资源路径,例如“/auth-required”

客户端可以将资源路径路由到具有登录/密码表单的模式,避免将用户转移到另一个页面。

【讨论】:

【参考方案10】:

对于非 Ajax 请求,我使用 302 重定向。

对于 Ajax 请求,我使用 200 表示 已知 错误。这样我就可以利用数据对象。我发现数据对象比解析 jqXHR 的信息更容易使用。然后我就不必担心要针对我的情况重新使用什么 HTTP 状态代码。

jQuery 示例:

$.ajax(
    //send data to server
)
.done(function(data, textStatus, jqXHR) 
    if (data.success) 
        //then process return data
    
    else 
        //get error type or message from data object
        //could use custom error codes
    
)
.fail(function(jqXHR, textStatus, errorThrown) 
    //handle unknown errors
);

【讨论】:

不想解析响应并不是偏离 HTTP 规范的好理由,尤其是当您可以只使用 JSON.parse(responseText) 时。 我不认为在这种情况下使用 200 响应代码会偏离 HTTP 规范,因为请求在传输层技术上是成功的。对我来说,会话​​超时类似于我返回用户友好错误消息的表单错误。这个问题的答案中表达的分歧清楚地表明 HTTP 规范确实没有为会话超时提供行业接受的响应代码。怎么可能偏离不存在的规范?【参考方案11】:

代码 408。“请求超时”,看起来很完美——RFC 2616 解释了它的意思

客户端没有产生请求 在服务器运行的时间内 准备等待。

即,完全符合您的要求!

【讨论】:

啊,但是看看定义的其余部分:“客户端可以在以后的任何时间重复请求而无需修改。” “未经修改”意味着可以通过重新加载/刷新请求来创建新会话。在大多数情况下,使用身份验证时,用户必须先重新登录。 @AJ,当然,重复的请求可能会遇到身份验证挑战(HTTP 代码 401)——在 HTTP 规范中看不到任何禁止那个的内容,你能指出什么? 408 告诉客户端他们应该尝试按原样重新提交请求,如果会话超时,这显然无法工作。 408 是“请求”超时而不是会话超时。意思是,套接字已建立但花费的时间太长。这个网站很好地解释了它:checkupdown.com/status/E408.html

以上是关于应该使用啥 http 状态代码来告诉客户端会话已超时?的主要内容,如果未能解决你的问题,请参考以下文章

当会话令牌无效时我应该使用啥状态码?

如果请求缺少必需的参数,我应该使用啥 HTTP 状态响应代码?

HTTP会话的使用与管理

04-cookies 会话跟踪技术

Django - cookies 会话跟踪技术

在 2 因素身份验证中使用啥 HTTP 状态