ChatGPT解决这个技术问题 Extra ChatGPT

重定向到登录页面时正确的 HTTP 状态代码是什么?

当用户未登录并尝试访问需要登录的页面时,重定向到登录页面的正确 HTTP 状态代码是什么?

我问是因为3xx response codes set out by the W3C 似乎 都不符合要求:

10.3.1 300 多项选择 请求的资源对应于一组表示中的任何一个,每个表示都有自己的特定位置,并且正在提供代理驱动的协商信息(第 12 节),以便用户(或用户代理)可以选择首选表示并将其请求重定向到该位置。除非它是一个 HEAD 请求,否则响应应该包含一个实体,该实体包含一个资源特征和位置列表,用户或用户代理可以从中选择最合适的一个。实体格式由 ContentType 标头字段中给出的媒体类型指定。根据用户代理的格式和能力,可以自动选择最合适的选项。但是,本规范没有为这种自动选择定义任何标准。如果服务器有首选的表示形式,它应该在 Location 字段中包含该表示形式的特定 URI;用户代理可以使用 Location 字段值进行自动重定向。除非另有说明,否则此响应是可缓存的。 10.3.2 301 Moved Permanently 请求的资源已经被分配了一个新的永久 URI,并且任何将来对该资源的引用都应该使用返回的 URI 之一。如果可能,具有链接编辑功能的客户端应该自动将对 Request-URI 的引用重新链接到服务器返回的一个或多个新引用。除非另有说明,否则此响应是可缓存的。新的永久 URI 应该由响应中的 Location 字段给出。除非请求方法是 HEAD,否则响应的实体应该包含一个简短的超文本注释,其中包含指向新 URI 的超链接。如果收到 301 状态代码以响应 GET 或 HEAD 以外的请求,用户代理不得自动重定向请求,除非用户可以确认,因为这可能会改变发出请求的条件。注意:当收到 301 状态码后自动重定向 POST 请求时,一些现有的 HTTP/1.0 用户代理会错误地将其更改为 GET 请求。 10.3.3 302 Found 请求的资源临时驻留在不同的 URI 下。由于重定向有时可能会改变,客户端应该继续使用 Request-URI 来处理未来的请求。此响应仅在由 Cache-Control 或 Expires 标头字段指示时才可缓存。临时 URI 应该由响应中的 Location 字段给出。除非请求方法是 HEAD,否则响应的实体应该包含一个简短的超文本注释,其中包含指向新 URI 的超链接。如果收到 302 状态码以响应 GET 或 HEAD 以外的请求,除非用户可以确认,否则用户代理不得自动重定向请求,因为这可能会改变发出请求的条件。注意:RFC 1945 和 RFC 2068 指定不允许客户端更改重定向请求的方法。然而,大多数现有的用户代理实现将 302 视为 303 响应,无论原始请求方法如何,都对 Location 字段值执行 GET。状态码 303 和 307 已被添加用于希望明确明确期望客户端做出何种反应的服务器。 10.3.4 303 See Other 可以在不同的 URI 下找到对请求的响应,并且应该在该资源上使用 GET 方法检索。此方法的存在主要是为了允许 POST 激活脚本的输出将用户代理重定向到选定的资源。新的 URI 不是原始请求资源的替代引用。 303 响应不能被缓存,但对第二个(重定向)请求的响应可能是可缓存的。不同的 URI 应该由响应中的 Location 字段给出。除非请求方法是 HEAD,否则响应的实体应该包含一个简短的超文本注释,其中包含指向新 URI 的超链接。注意:许多 HTTP/1.1 之前的用户代理不理解 303 状态。当考虑与此类客户端的互操作性时,可以使用 302 状态代码,因为大多数用户代理对 302 响应做出反应,如此处针对 303 所述。 10.3.5 304 Not Modified 如果客户端已执行条件 GET 请求和访问是允许的,但是文档没有被修改,服务器应该用这个状态码响应。 304 响应不能包含消息体,因此总是由头字段之后的第一个空行终止。响应必须包含以下标头字段: - 日期,除非第 14.18.1 节要求省略它 如果无时钟源服务器遵守这些规则,并且代理和客户端将自己的日期添加到没有收到的任何响应中(如已指定[RFC 2068],第 14.19 节),缓存将正确运行。 - ETag 和/或 Content-Location,如果标头将在对同一请求的 200 响应中发送 - Expires、Cache-Control 和/或 Vary,如果字段值可能与任何先前响应中发送的不同对于相同的变体如果条件 GET 使用了强缓存验证器(参见第 13.3.3 节),则响应不应包含其他实体标头。否则(即,条件 GET 使用弱验证器),响应不得包含其他实体标头;这可以防止缓存的实体主体和更新的标头之间的不一致。如果 304 响应指示当前未缓存的实体,则缓存必须忽略响应并在没有条件的情况下重复请求。如果缓存使用接收到的 304 响应来更新缓存条目,则缓存必须更新该条目以反映响应中给出的任何新字段值。 10.3.6 305 使用代理 请求的资源必须通过位置字段给出的代理访问。 Location 字段给出了代理的 URI。接收者应该通过代理重复这个单一的请求。 305 响应必须只能由源服务器生成。注意:RFC 2068 并不清楚 305 旨在重定向单个请求,并且仅由源服务器生成。不遵守这些限制会产生重大的安全后果。 10.3.7 306(未使用) 306 状态码在之前的规范版本中使用过,不再使用,该代码被保留。 10.3.8 307 临时重定向 请求的资源临时驻留在不同的 URI 下。由于重定向有时可能会改变,客户端应该继续使用 Request-URI 来处理未来的请求。此响应仅在由 Cache-Control 或 Expires 标头字段指示时才可缓存。临时 URI 应该由响应中的 Location 字段给出。除非请求方法是 HEAD,否则响应的实体应该包含一个简短的超文本注释,其中包含指向新 URI 的超链接,因为许多 HTTP/1.1 之前的用户代理不理解 307 状态。因此,注释应该包含用户在新 URI 上重复原始请求所需的信息。如果收到 307 状态代码以响应 GET 或 HEAD 以外的请求,则用户代理不得自动重定向请求,除非用户可以确认,因为这可能会改变发出请求的条件。

我现在使用 302,直到我找到正确的答案。

更新和结论:

HTTP 302 更好,因为它与客户端/浏览器具有最佳兼容性。

我会说绝对按书本的方式是返回一个 401 和一个没有重定向的登录页面,但我不确定你的选择是什么。
@Nick 好点,但如果我正在构建一个经典的登录系统,我会担心它的副作用。
@Pekka - 绝对同意,这取决于它在哪个平台上如何干净地处理所有这些,如果它是 Intranet 与 Internet 发挥作用,我相信......你通常在 Intranet 上以不同的方式进行身份验证,至少在我的经验中。
@Nick With 401“响应必须包含 WWW-Authenticate 标头字段”-如何将其与 MySQL 数据库结合使用? AuthType Basic 和 Digest 是否仅限于 .htpassword 等 apache 配置文件...?
我想要一个自定义登录页面,而不是要求用户名和密码的基本浏览器对话框......

P
Pekka

我会说 303 看到其他 302 Found:

请求的资源临时驻留在不同的 URI 下。由于重定向有时可能会改变,客户端应该继续使用 Request-URI 来处理未来的请求。此响应仅在由 Cache-Control 或 Expires 标头字段指示时才可缓存。

我认为最适合登录页面。我最初认为 303 see other 也可以。经过一番思考,我会说 302 Found 更合适,因为找到了请求的资源,只有另一个页面要经过才能访问它。默认情况下,响应不会被缓存,这也很好。


我同意,但我认为 302 Found 表明在另一个 url 下找到了资源。前任。我想用 302 se /my-messages/ 服务器回答,因为“今天”我的消息位于“/login/”(而不是“/messages/”)...我使用 302,但我不觉得上下文是 100% 匹配的。由于登录页面是不同的资源,并且与请求的内容不同。
@PHP_Jedi 是的。从这个角度来看,303 可能更合适。但是,在客户端兼容性方面,302 更可靠。
是的,我认为 303 可能更适合上下文,因为它声明“可以在不同的 URI 下找到对请求的响应”。这告诉我,在另一个 URI 中找到的不是资源本身,而只是对该请求的响应。
303 状态“此方法的存在主要是为了允许输出 POST 激活的脚本......”。对我来说不是这样......即使有一个POST,登录页面也不会输出它。例如,如果用户在“/my-messages/”中标记一些消息并发布删除。如果会话超时,登录页面不会输出任何这些 POST 参数。
@PHP_Jedi 我不确定是否值得花这么多时间。无论如何,http 世界中的客户端和服务器都必须非常自由和容错,因此无论您使用 302 还是 303 都没有真正的区别,只是 302 更为人所知。我发现细节水平值得称赞,把事情做好总是好的,但在这个特定领域,太多的努力可能是徒劳的。
C
Community

这是对 HTTP 重定向机制的误用。如果用户未获得授权,那么您的应用必须返回 401 Unauthorized。如果用户已获得授权但无权访问所请求的资源,则必须返回 403 Forbidden

您应该在客户端进行重定向,例如通过 javascript。重定向的状态码,因为所需的授权不存在。为此使用 30x 不符合 HTTP。

How to Think About HTTP Status Codes by Mark Nottingham

401 Unauthorized 触发 HTTP 的请求认证机制。

401 Unauthorized 状态代码需要存在支持各种身份验证类型的 WWW-Authenticate 标头:

WWW-Authenticate: 领域=<领域>

Bearer、OAuth、Basic、Digest、Cookie 等

超文本传输协议 (HTTP) 身份验证方案注册表

基于 Cookie 的 HTTP 身份验证 - DRAFT


在某些情况下,401 可能不适合用作 A server generating a 401 (Unauthorized) response MUST send a WWW-Authenticate header field (RFC),而且并非所有登录系统都使用该标头。
假设您正在刷新一个受保护的页面;客户端javascript不会有任何更改被调用,并且浏览器将弹出一个登录窗口而不是将用户重定向到登录页面 - 所以唯一的方法是使用30x代码。
Golang 不能使用 401 进行重定向。这意味着我们应该使用 30* 进行重定向。
@EIMEI 按照您的推理,如果另一种语言或库强迫您使用 401,那么互联网将注定失败。我的意思是:你所说的指向 Golang 的一个问题(尽管我发现它会有这样的设计使得无法发送 401 感到惊讶!)
@starbeamrainbowlabs 有一个基于 Cookie 的 HTTP 身份验证的草案作为 WWW-Authenticate 标头中的一个选项。请参阅:tools.ietf.org/html/draft-broyer-http-cookie-auth-00
D
Davis Peixoto

我认为适当的解决方案是 HTTP 401(未授权)标头。

http://en.wikipedia.org/wiki/HTTP_codes#4xx_Client_Error

此标头的目的正是如此。但是,正确的过程不是重定向到登录页面,而是如下所示:

未登录的用户尝试访问登录限制页面。

系统识别用户未登录

系统返回 HTTP 401 标头,并在同一响应中显示登录表单(不是重定向)。

这是一个很好的做法,例如提供有用的 404 页面、站点地图链接和搜索表单。

再见。


RFC 声明:“响应必须包含 WWW-Authenticate 头字段(第 14.46 节),其中包含适用于所请求资源的质询。” 401 响应仅在使用 HTTP 身份验证方案时才适用。
在那种情况下,403 会更好,因为它表明访问被简单地禁止并且授权标头无济于事
@bshacklett WWW-Authenticate 可以与许多身份验证方案(例如承载、OAuth)一起使用。请参阅 developer.mozilla.org/en-US/docs/Web/HTTP/Headers/…iana.org/assignments/http-authschemes/http-authschemes.xhtml
作为 WWW-Authenticate 标头中的一个选项,有一个基于 Cookie 的 HTTP 身份验证的草案。请参阅:tools.ietf.org/html/draft-broyer-http-cookie-auth-00
@aef 好点!但是基于 HTML 和 Cookie 的身份验证草案是从 2009 年开始的,从未获得批准。因此,对于基于 HTML 和 Cookie 的身份验证,401 仍然不是合适的重定向代码。
G
GlenPeterson

这里有很多令人信服和矛盾的回应!如何选择?

决赛选手:

302 找到

表示请求的资源已临时移动到 Location 标头给出的 URL。浏览器重定向到此页面,但搜索引擎不会更新其指向该资源的链接。规范要求执行重定向时方法(和主体)不被更改,但并非所有用户代理都符合。因此,建议仅将 302 代码设置为 GET 或 HEAD 方法的响应,并改用 307 临时重定向,因为在这种情况下明确禁止更改方法。 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302

模糊,可能有问题,可能已经过时,但可以工作,特别是对于 GET 请求。

307临时重定向

请求的资源已临时移动到 Location 标头给出的 URL。 307 和 302 的唯一区别是 307 保证重定向请求时方法和正文不会改变。对于 302,一些旧客户端错误地将方法更改为 GET:使用非 GET 方法和 302 的行为在 Web 上是不可预测的,而使用 307 的行为是可预测的。对于 GET 请求,它们的行为是相同的。 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307

我最初的看法是,如果您的应用程序支持 HTTP 1.1+,这将是进行临时重定向的更新、更清晰的方法。

401未经授权

指示客户端请求尚未完成,因为它缺少所请求资源的有效身份验证凭据。此状态代码与 HTTP WWW-Authenticate 响应标头一起发送,其中包含有关客户端如何在提示用户提供身份验证凭据后再次请求资源的信息。此状态码类似于 403 Forbidden 状态码,只是在导致此状态码的情况下,用户身份验证可以允许访问资源。

我同意这可能是为了成为正确的响应代码,即“在您登录之前不要”。但是几乎每个 web 应用程序都使用带有 Cookie 的 HTML 表单进行登录,并且此 HTTP 代码不允许将“Cookie”作为身份验证方案:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticatehttps://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml

一些人指出,有人在 2009 年起草了一个“Cookie”计划:WWW-Authenticate Cookie https://datatracker.ietf.org/doc/html/draft-broyer-http-cookie-auth-00 不知道为什么没有成功。也许是因为这超出了 HTTP 的范围?

如果没有“Cookie”作为选项,我认为这不适合基于 HTML 和 Cookie 的身份验证。

民意调查

在没有一个不可否认的单一“正确”答案的情况下,我查看了一些行业领导者正在做的事情。

谷歌:302重定向到登录页面

请求 URL:https://mail.google.com/mail/u/0/?tab=cm 请求方法:GET 状态码:302 响应:content-type:text/html; charset=UTF-8 位置:https://accounts.google.com/ServiceLogin?service=mail&passive=1209600&osid=1&continue=https://mail.google.com/mail/u/0/?tab%3Dcm&followup=https: //mail.google.com/mail/u/0/?tab%3Dcm&emr=1

Microsoft:302 重定向到登录页面

请求 URL:https://outlook.live.com/mail/0/?authRedirect=true&state=0 请求方法:GET 状态代码:302 响应:位置:https://outlook.live.com/owa/0/?状态=1&redirectTo=aHR0cHM6Ly9vdXRsb29rLmxpdmUuY29tL21haWwvMC8

Facebook:302 重定向到登录页面

请求 URL:https://www.facebook.com/friends 请求方法:GET 状态码:302 响应:位置:https://www.facebook.com/login.php?next=https%3A%2F%2Fwww。 facebook.com%2Ffriends

Twitter:200 个带插页式登录页面

请求 URL:https://twitter.com/messages/ 请求方法:GET 状态码:200(来自 service worker)

我:307:临时重定向

我已经使用了十多年,从来没有遇到过问题。不建议其他人采用它,只是说它在每个主要浏览器中都像宣传的 302 替代方案一样工作。由于研究了这个答案,我可能会被说服改用 302。

结论

302 是重定向的事实标准,除非您需要将 POST 重定向到另一个 POST,但我没有尝试过。

真的,我认为 POST 要么成功,要么彻底失败。 POST 会导致服务器上的状态更改(例如将产品添加到库存),您真的想知道更改是否已处理以及处理了多少次。重定向会引发在重定向之前您的更改是否被接受的问题。一旦您决定从不重定向 POST,则 302 和 307 是等效的。 302 中的“错误”出现在不切实际的用例中。因此,永远不应该创建 307。 302 也更受欢迎,因此可能得到最好的支持。

对所有临时重定向使用单个代码的好处是您不必担心重定向的原因。

200 与 JavaScript 抛出一个插页式登录页面是另一种选择,可能更适合单页 web 应用程序。您请求了该页面,您获得了该页面,但您将被迫登录才能看到内容。