HTTP 状态码 302,303,307

2023-07-16

最近一直在看《HTTP The Definitive Guide》,对此大家可能有点陌生,但是一提它的中文名称那就是耳熟能详了,它的中文书名是《http权威指南》.在看到HTTP Messages这一章Status Code这一节,发现状态码302、303、307这三个很相似,然后对此进行了对比,特此记录.

302 Found

This is an example of industry practice contradicting the standard. The HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect (the original describing phrase was "Moved Temporarily", but popular browsers implemented 302 with the functionality of a 303 See Other.Therefore, HTTP/1.1 added status codes 303 and 307 to distinguish between the two behaviours. However, some Web applications and frameworks use the 302 status code as if it were the 303 ——[1]

在看下维基百科的定义:

The HTTP response status code 302 Found is a common way of performing URL redirection.
An HTTP response with this status code will additionally provide a URL in the header field location. The user agent (e.g. a web browser) is invited by a response with this code to make a second, otherwise identical, request to the new URL specified in the location field. The HTTP/1.0 specification (RFC 1945) initially defined this code, and gives it the description phrase "Moved Temporarily".
Many web browsers implemented this code in a manner that violated this standard, changing the request type of the new request to GET, regardless of the type employed in the original request (e.g. POST).For this reason, HTTP/1.1 (RFC 2616) added the new status codes 303 and 307 to disambiguate between the two behaviours, with 303 mandating the change of request type to GET, and 307 preserving the request type as originally sent. Despite the greater clarity provided by this disambiguation, the 302 code is still employed in web frameworks to preserve compatibility with browsers that do not implement the HTTP/1.1 specification.
As a consequence, the update of RFC 2616 changes the definition to allow user agents to rewrite POST to GET ——[2]

结合上面两个我们大致可以总结出这样一些结论:

在 RFC 1945 中初次定义状态码302,并将其描述位"Moved Temporarily"(暂时移动).预期关于302的使用应该如下,当一个http的response状态码为302的时候,其响应头肯定回包含一个可选的URL(如下图).客户端预期需要根据该URL进行二次请求.正常情况下客户端的请求方式应该与之前保持一致,但是许多Web浏览器并没有遵守这个规定,而是不管原始请求使用何种类型,都将新请求的请求类型变为GET.由于这个原因,在HTTP/1.1 (RFC 2616)添加 303 和 307 这两个状态码,其中 303强制将请求类型改变为GET,307保留原始发送的请求类型. 而302则用来维持与尚未实现HTTP/1.1规范的浏览器的兼容性.

303 See Other (since HTTP/1.1)

The response to the request can be found under another URI using the GET method. When received in response to a POST (or PUT/DELETE), the client should presume that the server has received the data and should issue a new GET request to the given URI.

对于303我们从上面就可以得知,二次请求的方式一定为GET,如果第一次请求为其他类型的话,我们默认认为它已经接受到了数据.该状态码可以用来相应任何方式的HTTP请求.

它主要用于允许POST操作的输出将客户端重定向到选定的资源,因为这样做提供了与POST响应相对应的信息,并且该表单可以独立于原始请求单独标识、书签和缓存,个人理解是正常情况下我们在一个页面进行了post操作,然后得到服务器响应在当前页面获取到相应数据,显然这种情况下页面是无法保存书签和缓存的,一旦我们重新访问这个页面,之前的数据还是需要我们重新请求的,303则是将响应的内容重新定向到一个新的页面,并且下次访问该页面的时候响应的数据还是仍然存在的,比如消息确认页面或上传进度页面.

对于303响应GET方式的请求,我个人是有点困惑的.RFC7321表述内容如下:

A 303 response to a GET request indicates that the origin server does not have a representation of the target resource that can be transferred by the server over HTTP. However, the Location field value refers to a resource that is descriptive of the target resource, such that making a retrieval request on that other resource might result in a representation that is useful to recipients without implying that it represents the original target resource. Note that answers to the questions of what can be represented, what representations are adequate, and what might be a useful description are outside the scope of HTTP. ——[3]

直观的翻译大意如下:
对GET请求的303响应表明,源服务器不具有可由服务器通过HTTP传输的目标资源的表示形式。但是,Location字段值是指描述目标资源的资源,因此,对该其他资源发出检索请求可能会导致对收件人有用的表示,而不会暗示它代表原始目标资源。

我的理解是对于GET方式返回303代表,其目标资源并不能很好的借由服务器通过HTTP协议很好的展示出来.响应头中的Location的值指的是一种资源,用来是描述目标资源的.对该资源请求可能获取到对客户端有用的信息.

307 Temporary Redirect (since HTTP/1.1)

In this case, the request should be repeated with another URI; however, future requests should still use the original URI. In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request. For example, a POST request should be repeated using another POST request

307就相对毕竟简单些,如果返回的状态码为307,则表明使用head中location的URI进行再一次的请求,但是以后的请求仍然使用原来的URI.与以往实现302的方式不同,在重新发出原始请求时,不允许更改请求方法。例如,应该使用另一个POST请求重复POST请求.

参考链接

[1] 3xx_Redirection

[2] HTTP_302

[3] 303 See Other