Related Questions:
For Which Redirection Responses are Location Headers Mandatory?
Is it Possible to Send a 401 Unauthorized and Redirect with a Location?
While trying to figure out how to send error responses for users in PHP, I came across these interesting questions above. In one of the answers to the 2nd question listed above, it was mentioned that the Location headers are ignored for responses other than redirects. I was looking at the HTTP/1.1 RFC and from what I have looked at, there is no mention of ignoring any Location headers within the spec.
So, is the Location header within an HTTP response actually ignored for response codes that are not classified as redirects (3XX)?
No, there are status codes where Location is relevant as well, such as 201 Created. It varies on status code, not status code class.
Related
My website has a 1% random chance of redirecting visitors to this YouTube video.
The server currently sends the good-old 302, but I want it to have better semantics.
I don't know if the redirect is permanent or temporary. It's permanent in the sense that people always have a 1% chance of being redirected, and it's temporary in the sense that people don't get redirected every single time.
None of the current 3xx response status codes match my website's behavior.
HTTP 3xx redirects (source: Wikipedia)
301 Moved Permanently
This and all future requests should be directed to the given URI.[21]
"This and all future requests" - nope, not all future requests.
302 Found (Previously "Moved temporarily")
Tells the client to look at (browse to) another url. 302 has been superseded by 303 and 307. 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"),[22] 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.[23] However, some Web applications and frameworks use the 302 status code as if it were the 303.[24]
This is confusing. It does state, "302 has been superseded by 303 and 307," so I guess this is obsolete yet still commonly used?
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.[25]
"The response to the request can be found under another URI" - Rickroll is not the response to the original request. It has nothing to do with my site! "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." The last sentence of the 303 description doesn't work with my redirect.
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.[30]
"In this case, the request should be repeated with another URI; however, future requests should still use the original URI." Yes! This is what my redirect is. "...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." Unfortunately, this doesn't work with my redirect. My site randomly Rickrolls users even when they submit forms (POST method).
308 Permanent Redirect (RFC 7538)
The request and all future requests should be repeated using another URI. 307 and 308 parallel the behaviors of 302 and 301, but do not allow the HTTP method to change. So, for example, submitting a form to a permanently redirected resource may continue smoothly.[31]
308 has the same issue as 301 because not all future requests should go to the Rickroll video. Furthermore, the method isn't allowed to change.
What HTTP response status code should my server send for random-chance redirects that have nothing to do with my actual site?
The official source for HTTP response status codes is RFC7231, not Wikipedia.
You should peruse RFC7231 Section 6.4 for the explanation of 3XX status codes.
The "redirecting visitors by random chance" thing is irrelevant to the actual redirection,
therefore the status code that fits your requirement is 303,
which is explained in Section 6.4.4 as follows (emphasis mine):
The 303 (See Other) status code indicates that the server is
redirecting the user agent to a different resource, as indicated by a
URI in the Location header field, which is intended to provide an
indirect response to the original request. A user agent can perform
a retrieval request targeting that URI (a GET or HEAD request if
using HTTP), which might also be redirected, and present the eventual
result as an answer to the original request. Note that the new URI
in the Location header field is not considered equivalent to the
effective request URI.
303 fits your requirement for three reasons:
"to a different resource": the resource your visitors are redirected to is not the same resource they originally requested.
"perform a retrieval request": the eventual resource is acquired using a GET or HEAD request.
"not considered equivalent": the original request URI must not be replaced by the new URI because it is not equivalent, in other words, it is temporary.
Why not 302?
Because of this part of the explanation in Section 6.4.3 (emphasis mine):
For historical reasons, a user agent MAY change the request
method from POST to GET for the subsequent request.
In other words, the user agent can use either the same request method or a different request method.
The flexibility that the specification allows for 302 doesn't fit your requirement.
I'm not sure which is the best to use for my site when redirecting from http to https.
At the moment I am using IIS rewrite rules to do the redirect. The guides I've read on how to do this use either a 301 or a 303. And after reading up on 301 and 303, I'm still not sure which is best to use.
My understanding is they are pretty much similar in what they do in regards to a redirect between http and https.
Is there any difference and will it affect SEO in any way using one over the other?
From the spec:
301
The 301 (Moved Permanently) status code indicates that the target
resource has been assigned a new permanent URI and any future
references to this resource ought to use one of the enclosed URIs.
Clients with link-editing capabilities ought to automatically re-link
references to the effective request URI to one or more of the new
references sent by the server, where possible.
The server SHOULD generate a Location header field in the response
containing a preferred URI reference for the new permanent URI. The
user agent MAY use the Location field value for automatic
redirection. The server's response payload usually contains a short
hypertext note with a hyperlink to the new URI(s).
Note: For historical reasons, a user agent MAY change the request
method from POST to GET for the subsequent request. If this
behavior is undesired, the 307 (Temporary Redirect) status code
can be used instead.
A 301 response is cacheable by default; i.e., unless otherwise
indicated by the method definition or explicit cache controls
303
The 303 (See Other) status code indicates that the server is
redirecting the user agent to a different resource, as indicated by a
URI in the Location header field, which is intended to provide an
indirect response to the original request. A user agent can perform
a retrieval request targeting that URI (a GET or HEAD request if
using HTTP), which might also be redirected, and present the eventual
result as an answer to the original request. Note that the new URI
in the Location header field is not considered equivalent to the
effective request URI.
This status code is applicable to any HTTP method. It is primarily
used to allow the output of a POST action to redirect the user agent
to a selected resource, since doing so provides the information
corresponding to the POST response in a form that can be separately
identified, bookmarked, and cached, independent of the original
request.
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.
Except for responses to a HEAD request, the representation of a 303
response ought to contain a short hypertext note with a hyperlink to
the same URI reference provided in the Location header field.
Google says:
Redirect your users and search engines to the HTTPS page or resource with server-side 301 HTTP redirects.
I recommend following Google's advice rather than trying to implement a 303 strategy.
Source: https://support.google.com/webmasters/answer/6073543?hl=en
When you redirect http to https, essentially you want to preserve the "link juice" from SEO perspective.
As you might know Google considers the number of backlinks a site has for ranking.
The main difference between the 301 and 303 redirect is essentially whether it passes link juice or not. There are technical differences like what you mentioned but from SEO perspective, 301 is a better choice.
Here is a blog post that shows how 303 might affect SEO of your site.
https://digitalreadymarketing.com/303-redirect-effect-seo/
In case you are interested in learning more about duplicate content (http and https is a typical duplicate content issue), check this post.
https://digitalreadymarketing.com/what-is-duplicate-content-how-to-find-solve-them/
What is the correct behavior expected of a POST => 302 redirect to GET?
In chrome (and likely most every browser), after I POST (to a resource that wants me to redirect) and I receive a 302 redirect, the browser automatically issues a GET on the 302 location. This is even a well known pattern. But the way I read the spec, it seems to suggest this should not happen.
The HTTP spec says
If the 302 status code is received in response to a request other than
GET or HEAD, the user agent MUST NOT automatically redirect the
request unless it can be confirmed by the user, since this might
change the conditions under which the request was issued.
And fiddler is showing:
REQUEST 1: POST URLA
RESPONSE 1: 302 redirect to URLB
REQUEST 2: GET URLB
The section above seems to say that the browser should not make the GET request? What am I missing?
Something earlier in the spec that makes this section irrelevant
My understanding of automatically redirect is wrong (and the chrome browser that did the GET wasn't really automatically redirecting)
My understanding of confirmed this as a user
Something else?
The very next line in the spec begins:
Note: RFC 1945 and RFC 2068 specify that the client is not allowed
to change the method on the redirected request. However, most
existing user agent implementations treat 302 as if it were a 303
response, performing a GET on the Location field-value regardless
of the original request method. The status codes 303 and 307 have
been added for servers that wish to make unambiguously clear which
kind of reaction is expected of the client.
And immediately after that, it explains how a 303 should be handled, and it's exactly what you're seeing.
If you're asking why servers are still using 302 instead of 307, which all current browsers will handle correctly, it's because old browsers won't handle it. If you're wondering why browsers handle 302 as 303, it's because old servers expect it. There's really no way out of that loop, and it would probably be better for HTTP to just revert 302 to mean what it used to mean, and deprecate it (for non-GET/HEAD) in favor of 307.
abarnert was right ! I had the same issue with Google App Engine but I found a different solution.
My issue with appengine was,I did a POST with a form to a GO formHandler at backend. But it was executed as follow.
request 1: GET /formHandler -> response 1: 302 Found
request 1: POST /formHandler -> response 1: 302 Found
request 1: GET /formHandler -> response 1: 200 Ok.
Additionaly I got
No 'Access-Control-Allow-Origin' header is present on the requested resource
Which was a CORS problem.
However the solutions turns out to be to use HTTPS instead of HTTP.
Then you will have
request : POST /formHandler -> response : 200 Ok
You may want to read http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p2-semantics-22.html#rfc.section.6.4.p.3, which tries to clarify the situation.
Note: In HTTP/1.0, the status codes 301 (Moved Permanently) and 302 (Found) were defined for the first type of redirect ([RFC1945], Section 9.3). Early user agents split on whether the method applied to the redirect target would be the same as the original request or would be rewritten as GET. Although HTTP originally defined the former semantics for 301 and 302 (to match its original implementation at CERN), and defined 303 (See Other) to match the latter semantics, prevailing practice gradually converged on the latter semantics for 301 and 302 as well. The first revision of HTTP/1.1 added 307 (Temporary Redirect) to indicate the former semantics without being impacted by divergent practice. Over 10 years later, most user agents still do method rewriting for 301 and 302; therefore, this specification makes that behavior conformant when the original request is POST.
RFC 2616 defines the Location header as:
The Location response-header field is used to redirect the recipient to a location other than the Request-URI for completion of the request or identification of a new resource
...
For 3xx responses, the location SHOULD indicate the server's preferred URI for automatic redirection to the resource.
AFAIK, for 3xx Redirection codes, the Location header is:
300 Multiple Choices : optional
301 Moved Permanently : required
302 Found : required
303 See Other : required
304 Not Modified : irrelevant
305 Use Proxy : irrelevant (?)
306 Switch Proxy : irrelevant (?)
307 Temporary Redirect : required
308 Permanent Redirect : required
But that's just from personal experience. Is there a standard that defines which HTTP codes require the Location header to be sent?
That is, for which 3xx codes should an HTTP client throw an exception when received without a corresponding Location header?
This question has been asked back in the days when RFC 2616 has still been the authority, so it looked like a fun research project now that RFCs 7230 to 7235 are in place. So, let's see what we've got here.
The Location header is now defined in RFC 7231, section 7.1.2:
The "Location" header field is used in some responses to refer to a specific resource in relation to the response. The type of relationship is defined by the combination of request method and status code semantics.
[…]
For 201 (Created) responses, the Location value refers to the primary resource created by the request. For 3xx (Redirection) responses, the Location value refers to the preferred target resource for automatically redirecting the request.
The section does not confine this header solely to the 3xx-range of status codes. In fact, the only status codes explicitly being mentioned are 201 (Created) and 303 (See Other). No word about this header being actually required by any status code, though.
The purpose of the 3xx-range of codes is now described by RFC 7231, section 6.4:
The 3xx (Redirection) class of status code indicates that further action needs to be taken by the user agent in order to fulfill the request. If a Location header field is provided, the user agent MAY automatically redirect its request to the URI referenced by the Location field value, even if the specific status code is not understood.
The wording suggests that neither the presence nor automatically redirecting to its content is mandatory.
At the time of this writing, the IANA HTTP Status Code Registry is listing the codes 300 through 308 as registered. With one (305) being obsoleted and one being reserved (306), this is leaving seven active codes:
300: Multiple Choices – RFC 7231, section 6.4.1
The 300 code is to be returned if the server is aware of multiple representations of a resource. As of RFC 7231, there is no longer a recommended way to communicate a list of possible representations, though the Link header via RFC 5988 is being mentioned. Regarding the Location header, the RFC has this to say:
If the server has a preferred choice, the server SHOULD generate a Location header field containing a preferred choice's URI reference. The user agent MAY use the Location field value for automatic redirection.
Meaning the Location header is only to be used if the server has a preferred representation. If there is none, the server simply doesn't have such a preference.
It bears mentioning that the Location header by itself is unfit to list all possible representations as it is by its grammar a single-value field that cannot contain a list. Hence, the meaning of
Location: //example.com/a
Location: //example.com/b
is undefined.
301: Moved Permanently – RFC 7231, section 6.4.2
This response code is to let the client know there is an entirely new location for the requested resource: subsequent requests are to be directed at the location specified in the Location header.
The server SHOULD generate a Location header field in the response containing a preferred URI reference for the new permanent URI. The user agent MAY use the Location field value for automatic redirection.
Again, the presence of the Location header is no absolute requirement. The absence of this header would have questionable practicability. The semantics were akin - but not equal - to the 410 (Gone) response: "This resource is has permanently moved to a new, yet unknown location."
302: Found – RFC 7231, section 6.4.3
Originally this is has been specified as "Temporary Redirect" and got renamed in later specs. In contrast to 301 this one cannot (or should not) be cached or used to permanently rewrite URLs. The relevant part of the spec reads:
The server SHOULD generate a Location header field in the response containing a URI reference for the different URI. The user agent MAY use the Location field value for automatic redirection.
I believe the semantics of a missing Location header were pretty much the same as with 301: "This resource is has temporarily moved to a new, yet unknown location."
303: See Other – RFC 7231, section 6.4.4
303 is supposed to be returned in response to a POST request but is applicable to any method. In general, it is meant to let the client know there were a more appropriate representation at a substitute URL or the requested resource cannot be transmitted via HTTP.
In the context of this question, this is a bit of a headscratcher. RFC 2616, section 10.3.4 states:
The different URI SHOULD be given by the Location field in the response.
The relevant section of the newer RFC 7231 seems to simply presume the Location header being present:
the server is redirecting the user agent to a different resource, as indicated by a URI in the Location header field
There is nothing in the errata to clarify this, so I am inclined to assume the position of RFC 2616. The semantics of an absent Location header do differ depending on request method:
For POST this would be the same as 201 (Created) or 202 (Accepted)
For any other method, this were identical to 404 (Not Found)
304: Not Modified – RFC 7232, section 4.1
This response is in a way special as it stresses out on the "[indication] that further action needs to be taken by the user agent in order to fulfill the request." It should be understood as a redirect not to a new URI but to a local cache. There is no mention of the Location header in the relevant parts of RFC 7232 at all. In fact, this would make little sense as to my understanding the semantics were something like "the requested presentation of this entity has remained unchainged and you will find it in your local cache at …" That were a great breach of separation of concerns but is not to say Location were not allowed at this place. Still, Content-Location or a Link header with a rel=self part were more appropriate. Former one is receiving explicit mentioning:
The server generating a 304 response MUST generate any of the following header fields that would have been sent in a 200 (OK) response to the same request: Cache-Control, Content-Location, Date, ETag, Expires, and Vary.
305: Use Proxy – RFC 2616, section 10.3.6; RFC 7231, section 6.4.5
This status code has been deprecated as of RFC 7231 due to security concerns (cf Appendix B). Its definition in RFC 2616 reads:
The requested resource MUST be accessed through the proxy given by the Location field.
This implies the presence of a Location header, yet it does not explicitly require it. Omitting this header would have the semantic meaning of "this resource can only be accessed through some proxy."
306: Switch Proxy – draft-cohen-http-305-306-responses-00
Ths code has been introduced as a draft after RFC 2068 has been finalized and already got obsoleted by RFC 2616. To my knowledge, this draft has never reached the status of a recommendation, so this is purely for completeness. The rationale of this draft is to supply proxies with a mechanism to direct clients (temporarily) to other proxies for subsequent requests.
Part of this draft is the introduction of the Set-Proxy header which is to be used in place of the Location header per section 2.2:
In the original HTTP/1.1 spec, the 'Location' header was used to indicate the proxy setting. Its use is DEPRECATED by the 'Set-proxy' header in the context of a 305 response. All new implementations MUST send the Set-proxy header. Implementations MAY send the 'Location' header so as to allow backward compatibility.
Set-Proxy is then required in context of 306 while the Location header is purely optional. As the required Set-Proxy mechanism is meant to replace Location, the absence of latter header introduces no semantic changes.
307: Temporary Redirect – RFC 7231, section 6.4.7
307 got introduced as a result of a semantic change of 302 in HTTP/1.1: While redirects via 302 can change request methods, the redirected request must have the same request method as the original request.
The relevant part of the spec reads:
The server SHOULD generate a Location header field in the response containing a URI reference for the different URI. The user agent MAY use the Location field value for automatic redirection.
Again, Location seems to be optional. For semantic changes due to an absent header, see 302.
308: Permanent Redirect – RFC 7538
Like 307, redirects via 308 are to keep their original request method. One could say 308 were to 301 as 307 is to 302.
From section 3 of the spec:
The server SHOULD generate a Location header field in the response containing a preferred URI reference for the new permanent URI.
So, in summary we have got this situation:
Implied: 1 (305)
Optional: 1 (306)
No mention: 1 (304)
SHOULD: 6 (300; 301; 302; 303; 307; 308)
That "SHOULD" is to be read in the context of RFC 2119:
This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.
This is different from the absolute requirement of a "MUST" or "REQUIRED" (also in that RFC). So in a nutshell: There is no 3xx-class code in which the Location header is mandatory.
It should be noted, that the problem of a missing Location header is not a new one. From another answer:
301, 302, 303, and 307 provide a Location only if the next URL is known. Otherwise, the client/user has to decide what to do next
Say I'm sending some HTTP status code in PHP, do I actually need to do
header('HTTP/1.1 301 Moved Permanently');
or is it enough to
header('HTTP/1.1 301 FooBar');
I once did this in a quick and dirty reverse proxy, where I could only get the code, not the message, from a CURL response and sent it back with FooBar as message. This appeared to work fine.
Via the spec:
The individual values of the numeric status codes defined for
HTTP/1.1, and an example set of corresponding Reason-Phrase's, are
presented below. The reason phrases listed here are only
recommendations -- they MAY be replaced by local equivalents without
affecting the protocol.