Summary

  • RFC 1945 in May 1996 called 302 “Moved Temporarily” and required user confirmation before automatically redirecting a POST. RFC 2068 in January 1997 retained the caution, noted that some clients nevertheless changed POST to GET, and defined 303 “See Other” for retrieval with GET.
  • RFC 2616 in June 1999 renamed 302 “Found” and said most existing user agents treated it like 303, performing GET at the Location regardless of the original method. It added 307 “Temporary Redirect” to make method preservation clear; 303 had already appeared in 1997.
  • RFC 9110 in June 2022 still permits a user agent to change POST to GET after 302 for historical reasons. Under 307, an automatically redirected client must not change the method. Those choices determine whether a submitted body follows the redirect.

The form reaches a temporary address

The HTTP/1.0 specification published as RFC 1945 in May 1996 described status 302 as “Moved Temporarily.” A requested resource was at another URL for the moment. The server supplied that URL in Location, and the client was meant to keep using the original address for future requests because the move might change. For a simple GET, the route is easy to picture: ask for a document here, receive a temporary pointer, then retrieve it there.

POST complicates the picture. A user might have submitted a filled form or asked a server to perform an action. Should the client repeat that same operation at the new address? The 1996 text said that after a POST receives 302, the user agent must not automatically redirect unless the user can confirm it. The problem was not the new URL alone. Sending a request with a body to another target could change the conditions under which the user had chosen to submit it.

A redirect therefore has two separate dimensions. One is where the next request goes; Location supplies the destination. The other is what request goes there. Repeating POST carries the submitted method and, potentially, its body to the new server. Switching to GET asks for a resource without replaying that submission. Treating 302 as a mere change of address misses the second decision.

The early text did not present a neat diagram with a code for each possible answer. It imposed a brake on automatic POST redirection. That brake made sense in a world where the user had clicked Submit, not necessarily agreed to send the same contents to a different endpoint. It also left implementers facing the practical desire to show the user a results page after an action.

303 supplied one answer, browsers supplied another

The HTTP/1.1 specification RFC 2068, published in January 1997, kept 302 “Moved Temporarily” and continued to require confirmation before an automatic redirect of a request other than GET or HEAD. It recorded a crack in practice: some existing HTTP/1.0 user agents changed POST to GET when automatically following 302. The document called that behavior erroneous under the rule it was describing.

The same 1997 specification defined 303 “See Other.” A server could answer a POST by pointing to another URI whose representation should be retrieved with GET. The response from a script activated by POST was a chief use case. This was a clean statement of intent: process the submitted operation at the first endpoint, then fetch a separate result document. The new URI was not a substitute name for the original resource.

That distinction matters to both halves of the exchange. A server author using 303 asks for a retrieval after the POST. A client that converts 302 to GET makes a similar move even when the server used an older, ambiguous code. The destination might receive a harmless read request instead of another form submission. The browser's choice could also frustrate a server that expected the original POST to continue at the temporary location. One code was carrying two operational stories.

The 1997 text is valuable precisely because it names the mismatch while it is happening. It does not need a later historian to infer that browser behavior differed from the normative description. The implementers were already moving a request across the line from POST to GET, and the specification itself recorded the divergence.

The 1999 text admits what clients were doing

By June 1999, the revised HTTP/1.1 specification RFC 2616 made the conflict impossible to hide. It renamed 302 “Found.” In its note on 302, it said the 1996 and 1997 specifications had not allowed a method change, yet most existing user agents treated 302 as if it were 303: they made a GET request to the Location value regardless of the original method. The word “most” is the standard's own assessment of contemporary clients, not a measured count of browser versions in this article.

The document gave servers clearer tools. 303 continued to mean “See Other”: retrieve a different resource with GET, especially as the visible result of an action triggered by POST. That code was present in RFC 2068 already. The 1999 addition was 307 “Temporary Redirect,” intended to make the opposite choice unambiguous: the client could follow a temporary new URI while keeping the original request method. The two codes told a client whether the action should become a retrieval or remain the same kind of request.

The new distinction did not erase 302. The 1999 RFC even noted that many older clients did not understand 303 and that servers concerned with those clients could use 302 because most reacted to it as they would to 303. That is a blunt piece of interoperability advice. The clean semantic code existed; the population of running browsers pushed servers toward the old, overloaded one.

For a web developer, the stakes could be concrete. After a completed form submission, a GET of a results page is usually a different operation from resending the form body. A server that expects a POST at the redirected URI needs the client to preserve method and body. A server that merely wants to show the output of the first POST wants a retrieval. The status code carries the intended second step; choosing 302 after clients diverged left that step to historical convention.

A habit becomes permitted language

The 2022 HTTP Semantics specification, RFC 9110, still bears the mark of the old split. Its 302 section says a user agent may change the request method from POST to GET for the subsequent request, for historical reasons. That is permission, not a command to do so. If the server does not want this behavior, the specification points to 307. Under 307, a user agent that automatically redirects must not change the method.

The same document describes 303 as an indirect response: the user agent can retrieve a different resource, typically with GET or HEAD, and show that result as the answer to the original request. Its historical explanation says early agents split between preserving POST and changing it to GET, and prevailing practice converged on the latter for 301 and 302. The standard adapted its language to a network that had already chosen a convention.

The choice is not a contest in which preserving POST is always the brave, correct answer. Keeping POST means the submitted request, including a body, can travel to the URI in Location. That is precisely what a method-preserving redirect is for, and precisely why the server author must consider the new destination. Changing to GET avoids replaying the POST body, but it cannot perform an operation that genuinely must continue as POST at the new URI. The status must express the intended journey of the request, not an aesthetic preference for one number.

One piece of evidence remains outside these standards texts: they do not enumerate the browser releases that first made each choice. Dated implementation records would supply that chronology. The primary standards already document the crucial sequence: a 1996/1997 rule, a divergence recorded in 1997, a majority-practice admission and new code in 1999, and the historical permission still present in 2022.

The method was the payload of the dispute

HTTP's redirect codes are often described as signposts for moved pages. The 302 episode shows why that picture is too small. A POST can carry a user's decision and data. Sending it again to a new URI is not the same act as retrieving a page there. Location identifies the new place; the status code and client behavior decide what crosses the border.

Running browsers made one answer widespread. The protocol writers did not simply declare their own earlier instruction victorious. They named the gap, gave servers a clearer method-preserving code, and eventually allowed the old POST-to-GET behavior under 302. The standard had to govern software already in circulation. It could clarify future choices, but it could not make the installed browsers forget what they had been doing.

The oddity survives in a practical rule of reading: 302 can lead a POST to GET; 303 calls for a retrieval of another resource; 307 preserves the method on an automatic temporary redirect. Three nearby numbers describe different fates for the same form submission. One of them became ambiguous because the clients had answered the question before the paper caught up.

Sources