Do you always REDIRECT after POST? If yes, How do you manage it?

Jay picture Jay · Jul 5, 2009 · Viewed 12.6k times · Source

Say, you are submitting a form, which affects your database (adding records/ deleting them/ updating them) and this is how your request looks like:

POST /application/action=update

Now, say, you are done with your update, so you would like to take the user to the home page.

Response.sendRedirect /application/action=home

This works wonderfully well. User is sent a redirect after POST, so even if the user tries to refresh the page by hitting F5, you are good. However, this will not work if you did this:

requestDispatcher.forward(/application/action=home)

Given that there is a scenario where you have to display different kinds of error / success messages after you are done with your update, you are most likely doing a forward after POST. In such a scenario, how do you avoid update actions from happening twice?

I find it rather amusing that many secure sites (banks) / payment gateways tend to inform the user by placing text on screen, such as "Please don't press back / refresh buttons".

Is there no better way to handling this? Other than requesting the user not to press these buttons? When I last checked, there was something called the 'Vertical Response Cache'. A Filter that would identify uniqueness of your request in a session and tries to send a cached response if the request is duplicate. Are there any simpler ways to solving this classic problem?

Here is a link to the vertical response cache solution I was talking about: http://www.fingo.info/en/articles/_1.html. I am, However, not sure as to how well this really works.

Answer

Laurence Gonsalves picture Laurence Gonsalves · Jul 5, 2009

Yes, I believe that you should redirect after a POST, with the exception of API requests. Without doing this not only do you have to worry about getting duplicate POSTs when the user uses the back button, but the browser will also give the user annoying dialogs when they try to use the back button.

Response.sendRedirect works in practice, but tecnically speaking this is sending the wrong HTTP response code for this purpose. sendRedirect sends a 302, but the correct code to use to transform a POST into a GET is 303. (most browsers will treat a 302 just like a 303 if they get it in response to a POST, however)

In general you want the redirect to send the user to whatever view will display the effect of their change. For example, if they edit a widget, they should be redirected to the view of that widget. If they delete a widget, they should be redirected to the view that the widget would have appeared in when it existed (perhaps the widget list).

Sometimes it's nice to have a status message to further drive home the fact that an action occurred. A simple way to do this is to have a common parameter to your views that, when set, will display an action completed message. eg:

/widget?id=12345&msg=Widget+modified.

Here the "msg" parameter contains the message "Widget modified". The one downside to this approach is that it may be possible for malicious sites to give your users confusing/misleading messages. eg:

/account?msg=Foo+Corp.+hates+you.

If you're really worried about this you could include an expiring signature for the message as an additional parameter. If the signature is invalid or has expired, simply don't display the message.