226

HTTP redirects are done via HTTP codes 301, and 302 (maybe other codes also) and a header field known as "Location" which has the address of the new place to go. However, browsers always send a "GET" request to that URL.

However, many times you need to redirect your user to another domain via POST (bank payments for example). This is a common scenario, and really a requirement. Does anybody know why such a common requirement has been neglected in HTTP specification? The workaround is to send a form (with parameters in hidden fields) with action set to the target location (the value of the Location header field) and use setTimeout to submit the form to the target location.

0

3 Answers 3

228

In HTTP 1.1, there actually is a status code (307) which indicates that the request should be repeated using the same method and post data.

As others have said, there is a potential for misuse here which may be why many frameworks stick to 301 and 302 in their abstractions. However, with proper understanding and responsible usage, you should be able to accomplish what you're looking for.

Note that according to the W3.org spec, when the METHOD is not HEAD or GET, user agents should prompt the user before re-executing the request at the new location. You should also provide a note and a fallback mechanism for the user in case old user agents aren't sure what to do with a 307.

Using this form:

<form action="Test307.aspx" method="post">
    <input type="hidden" name="test" value="the test" />
    <input type="submit" value="test" />    
</form>

And having Test307.aspx simply return 307 with the Location:http://google.com, Chrome 13 and Fiddler confirm that "test=the test" is indeed posted to Google. Of course the further response is a 405 since Google doesn't allow the POST, but it shows the mechanics.

For more information see List of HTTP status codes and the W3.org spec.

307 Temporary Redirect (since HTTP/1.1) In this occasion, the request should be repeated with another URI, but future requests can still use the original URI.2 In contrast to 303, the request method should not be changed when reissuing the original request. For instance, a POST request must be repeated using another POST request.

3
  • 2
    @DavidRuttka, What's the browser support in the wild?
    – Pacerier
    Commented May 12, 2014 at 9:32
  • 7
    @DavidRuttka you might want to update your answer to take rfc7231 into account (obsoletes rfc2616). Prompting the user is based on a requirement in rfc2616. This requirement is dropped in rfc7231 and rfc7231 also introduces the requirement that 307 redirects must not change request method (which you mention in your quote a the end of your answer).
    – nibarius
    Commented Oct 22, 2014 at 6:39
  • Note that according to tools.ietf.org/id/draft-hunt-http-rest-redirect-00.html "HTTP redirection codes 301-306 SHOULD NOT be used unless the service provider is aware the client is in fact a user-agent" So it seems ReSTful services should use 308 instead of 301. However this is only a draft. Commented Nov 22, 2018 at 15:37
55

I found a good explanation on this page here.

The simplest situations on the WWW are "idempotent" transactions, i.e those which can be repeated without causing any harm. These are typically "GET" transactions, either because they are retrieval of straightforward URL references (e.g href= or src= attributes in HTML), or because they are form submissions using the GET method. Redirecting a transaction of that kind is straightforward, and no questions asked: the client receives the redirection response, including a Location: header that specifies the new URL, and the client reacts to it by re-issuing the transaction to the new URL. There's a difference between the different 30x status codes associated with these redirections in their implied cacheability, but otherwise they are basically similar (301 and 302) in response to GET requests.

POST transactions are different, since they are defined to be, in principle, non-idempotent (such as ordering a pizza, casting a vote or whatever) and mustn't be arbitrarily repeated.

The HTTP protocol specifications are designed to take this distinction into account: the GET method is defined to be inherently idempotent, whereas the POST method is defined to be, at least potentially, non-idempotent; the specifications call for a number of precautions to be taken by client agents (such as browsers) for protecting users against inadvertently (re)submitting a POST transaction which they had not intended, or submitting a POST into a context which they would not have wanted.

While I am not a fan of restricing users technically to prevent them from causing unwanted mayhem or doing unwanted harm to their applications, I can understand the point and it makes sense.

7
  • 1
    much of the reasoning goes to the days when the intertubes were slow and unreliable (which they still are in many locations of the world). I distinctly remember when I used dial up and would randomly be disconnected whenever someone else picked up the phone. It was better to reload the page and see what state the server was in than to resubmit things and run the risk of performing the same action twice.
    – zzzzBov
    Commented Aug 10, 2011 at 13:55
  • @Falcon, Would increasing the "visitor counter" be considered non-idempotent? If so, almost no websites these days do idempotent GETs...
    – Pacerier
    Commented May 12, 2014 at 9:35
  • @Pacerier: Typically idempotent is interpreted to be "idempotent in a meaningful way", for example, buying the same item twice, not clocking two visits. Otherwise, you'd be quite right. But really, the spec should have required servers to be meaningfully idempotent where necessary, such as embedding an ID in the page to prevent duplications -- not requiring the browser to ask the user a question they have no way of answering with any accuracy. Regardless, preventing a redirect of a POST does not affect idempotency; it's simply a message saying the target of the request is actually over there. Commented Jan 28, 2016 at 23:30
  • 1
    I think the important distinction is safe vs unsafe, not idempotent vs non-idempotent. It would be quite possible to implement pizza ordering system using idempotent PUT requests, where for example the request has to include an order ID and if you repeat it it just overwrites the previous order with that ID. But you'd still want to know whether you were ordering pizza or not.
    – bdsl
    Commented Mar 11, 2018 at 10:31
  • 1
    @b01 a POST request isn't necessary to redirect to a form with pre-populated data. Semantically you are just getting a form that has some stuff pre-filled, you aren't asking for the server to perform an action on your behalf. A get request has no body so the data to be pre-populated would have to either be stored on the server or in the URI, or a cookie etc.
    – bdsl
    Commented Mar 11, 2018 at 10:35
4

GET (and a few other methods) are defined as 'SAFE' in the http spec (RFC 2616):

9.1.1 Safe Methods

Implementors should be aware that the software represents the user in their interactions over the Internet, and should be careful to allow the user to be aware of any actions they might take which may have an unexpected significance to themselves or others.

In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested.

Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them.

This means that a GET request should never have any serious consequence for the user, beyond seeing something they might not want to see, but a POST request could change a resource that's important to them, or to other people.

Although this has changed with JavaScript, traditionally there were different user interfaces - users could trigger GET requests by clicking links, but would have to fill in a form to trigger a POST request. I think the designers of HTTP were keen to maintain the distinction between safe and non-safe methods.

I also don't think it should ever be necessary to redirect to a POST. Any action that needs to be carried out can presumably be done by calling a function within the server side code, or if it needs to happen on a different server then instead of sending a redirect containing a URL for the browser to POST to, the server could make a request to that server itself, acting like a proxy for the user.

2
  • One could make the exact same argument with GET as well. "Any action that needs to be carried out can presumably be done by calling a function within the server side code, or if it needs to happen on a different server then instead of sending a redirect containing a URL for the browser to POST to, the server could make a request to that server itself, acting like a proxy for the user" Commented Jan 27, 2021 at 16:35
  • "I also don't think it should ever be necessary to redirect to a POST" I actually need this to redirect my user from my site to a third party app, where there is a SAML endpoint that only accepts a (xml) SAMLResponse body via POST. I'm having to revert to javascript to do a two part redirect, which is a bit shitty. Commented Feb 19 at 17:51

Not the answer you're looking for? Browse other questions tagged or ask your own question.