"First they will ignore you, then they will laugh at you,  then they will fight you, then you will win."
- Mahatma Gandhi

Wednesday, November 19, 2008
       
  
Blogs

Search Blogs

The only thing to fear of the back button… is fear itself
Location: BlogsDoug's Blog   
Posted by: Doug.Danoff3/11/2007

Most of my projects over the last several years have included an interactive website component, one designed primarily to capture information from the user.  My topic today is about how these websites deal with the browser controls such as the dreaded Back, Forward, Refresh, and Bookmark.

I’ve never encountered a deeper “religious” reaction from engineers (including myself) than on this issue.  Many issues reach this level, but none have exceeded it.

Another characteristic of this issue is that it is often dismissed by the business users as minutia.  The issue is a bit complex to understand, but I believe the real reason business dismiss it is because they are not driven to fully confront the related questions until it is too late to do something about it.

So what’s the problem?

Technically speaking, the issue’s core is this “POST/FORWARD” (PF) scenario (non-techies, please bare with me):

  1. User enters data into a page and submits to the server using a POST
  2. Server processes the data and renders the resulting page by FORWARDING from within the server
  3. Browser believes the correct path to the result page is to submit the original POST

NOTE: In ASP.NET, Forward is accomplished with Server.Transfer().

This wreaks havoc on the browser’s navigational controls.  If the user navigates back to the page using, say, the back button, the browser tries to resubmit the original POST it knows will retrieve that page.  This is evidenced thru the all too common “Your browser needs to resend information you have previously submitted” message.

This situation can also cause severe application issues if it is not dealt with in some way. The resubmission of the POST causes the server to process the POST again.  If the POST was a request to charge a credit card, or add an item to a shopping cart, you may end up with an unintended duplicate of either of these items.

How people are addressing this problem

I’ve seen several “creative” solutions for this exact problem.  I’ll start with the ones I don’t like:

Warn the user to not click the back button
Some text on some page tells the user to not use the back button.  I guess this works in some cases, but c’mon… we can to better.

Disable browser navigation
Yes, there are ways to do this; and yes, people try.  This one is particularly frustrating to me.  The first reason is that you cannot fully disable all browser navigation.  The second reason is it goes against the general concepts of web browsing.

Warn the user if they navigate away
A major ramification of POST/FORWARD is that a user cannot reliably navigate to a page using the back button.  This includes situations where they accidentally click a link or otherwise navigate to another URL.  This can be annoying if the user had nearly completed a multi-page interview, and accidentally clicks the browser’s “Home” button.  A common solution for this is to try to intervene when the user leaves a page, using Java script to display a message box allowing them to cancel the “navigate away” command.
My major complaint with this solution is that if the user does navigate away, there is often no way back into the interview, unless the application specifically accommodates for this.

Use some variation of the token solution
Basically, a unique “token” is added to the form when it is first rendered.  The server compares it upon submit to something held in session.  This allows the application to prevent a page submission from being processed twice, and to take some alternate action when double submission happens.
This solution has a popular following with Java/Struts and has some applicability for this problem.  It might be a good solution in some applications for performance reasons.  I believe this is not the optimal solution.  The browser still attempts to POST data when the user really wants to view.  This solution addresses the symptom, not the problem.  Proper implementation of this solution requires substantial logic for supporting reentry and determining where to forward the user in various situations.

Use thick-client instead of a browser
Modern thick-client technologies (such as WinForms with remoting or web services) are sometimes employed to provide a custom UI for certain problems.  This avoids the need to support browser navigation all together by removing it from the paradigm.  If this is an option, it is worth considering.

A better way?

I have always intuitively believed that pages should be displayed using an HTTP GET.  I believed this even before I fully understood the difference between GET and POST.

To say this in plain English, what you see in your browser window should depend on the URL you navigated to, and not the decision made by the server when you last submitted data.

The first interactive website I ever wrote REDIRECTED the user to the correct page after processing form submissions.  That is, the server told the browser where to go next.  As I began working with other web applications, I was surprised to find this was not ‘yet’ the standard way to get the user to the next page.  I was surprised that the “POST/FORWARD” scenario discussed above was as prevalent as it actually is.

As I have studied this issue over the years, I’ve found that I am not alone in my beliefs.  There are various “movements” encouraging an alternative to “POST/FORWARD”.  One movement is named “POST/REDIRECT/GET” (PRG).  Another one is called “GET after POST”.  Hopefully these names are self-explanatory enough...  These are both the same thing:

  1. User enters data into a page and submits to the server using a POST
  2. Server processes the data and sends a REDIRECT instruction to the browser
  3. Browser issues a GET statement back to the server to get the next page

I won’t go into detail about these solutions.  I encourage you to read thru the referenced links get a full understanding of the solution.  But I will support the conclusion that this model solves most, if not all, browser navigation issues caused by POST/FORWARD.

Concerns with PRG

Like I said, people seem to be religious about this issue.  I suppose I’m guilty of this myself.  Here are the concerns people have raised with the pattern, and my responses to them:

2 Trips to the server?  PERFORMANCE WILL BE HORRID!!!
PRG does, indeed, require 2 trips to the server.  The first trip POSTS the form data, and the second GETS the resulting page.  This is not as bad as it sounds.  The intermediate redirect should cause a negligible performance difference in these kinds of applications.  It is possible that this performance difference is not acceptable in all cases, but I encourage a knowledgeable understanding (POC testing) before throwing the baby out with the bath water.

Business data on the query string? SECURITY!! DANGER!! DANGER!! SECURITY!!
PRG usually requires some identification information to be included on the GET query strings.  This is not to say that all business data is passed on the query string, only that the GET statement may need to identify what it is GETTING.  For example, if you have POSTED changes to one of your bank accounts, the application may want to redirect you to a detail page about that account like this:

            https://www.bank.com/DisplayAccount.aspx?account=checking123

In POST/FORWARD, it is not always necessary to display this query string, because the interaction occurs on the server.  Some argue that displaying this URL encourages fishing, where a malicious user could attempt to obtain other accounts by experimenting with other account numbers:

            https://www.bank.com/DisplayAccount.aspx?account=checking124
            https://www.bank.com/DisplayAccount.aspx?account=checking125
            https://www.bank.com/DisplayAccount.aspx?account=checking126

… etc.

My response to this important concern is this: in applications like this, IT IS IMPERATIVE that access-control security be employed to manage this security independently from what ever UI is used to display the data.  A more advanced hacker can attempt to alter the POSTED forms on similar fishing expeditions.  If security is a genuine concern, it MUST be dealt with separately.

Users expect this behavior.  WHY ARE YOU OVER ENGINEERING???
In POST/FORWARD, users are confronted with warnings, and usage conditions, and various other unpleasantries.  It is true that the savvy user has grown accustomed to these things.  But we have not yet reached the point where all users are of this level.  In fact, I have found that few users understand web with the depth we might expect.

Also, a simple warning-less site adds to the credibility of the site and the company.  It is usually important to provide as simple an experience as possible, especially if it is just as easy to accomplish… which brings me to my next point.

Implementing PRG is no more difficult than implementing PF.  In fact, I would argue implementing PRG is more natural and simple than PF.  PRG does introduce design questions that must be dealt with, but so does PF.

Strange scenarios still arise.  YOU HAVE NOT FIXED ANYTHING!!!
It is true that certain strange situations could happen.  Consider this scenario:

  1. User navigates to the Edit Bank Account page and closes the account with a POST to the server
  2. The server closes the account and instructs the browser to redirects to the List of Accounts page
  3. User clicks the back button to get back to the Edit Bank Account page, but the account has been cancelled

This highlights a certain kind of problem with browser navigation in general.  The problem does not disappear with PRG, but it is not worsened either.  In both cases, programmers must accommodate for this situation during page display.  Many other scenarios are fixed with PRG; it is not fair to say that it fixes “nothing”.

Conclusion – Use POST/REDIRECT/GET

Michael Jouravlev describes the PRG mantra as (quote):

Never show pages in response to POST
Always load pages using GET
Navigate from POST to GET using REDIRECT

After a pretty thorough study of the topic and options, I am fully behind this approach.  I recognize that it does not fix every problem with using the browser paradigm to supply an interactive UI.  But PRG fixes a fundamental problem with the PF approach, and allows application development to begin on a solid foundation.

References

Several of these links are JAVA specific, but the underlying technology we are addressing is Web, not language.  These articles are directly applicable to our problem -- for the most part.

Michael Jouravlev has written a good article on PRG.  The article suffers slightly from ESL, but the concepts are solid.
http://www.theserverside.com/tt/articles/article.tss?l=RedirectAfterPost

Michael Jouravlev’s article was preceeded with this post
http://www.theserverside.com/patterns/thread.tss?thread_id=20936

AdamV has compiled a brief summary of his experiences:
http://adamv.com/dev/articles/getafterpost

The difference between Response.Redirect() and Server.Transfer() in ASP.NET.  Warning, Karl says discusses using Server.Transfer() for Wizards…  don’t listen to him :):
http://www.developer.com/net/asp/article.php/3299641

Some related links:
http://www.theserverside.com/news/thread.tss?thread_id=41285
http://keithdevens.com/weblog/archive/2002/Apr/18/GETAfterPOST
http://www.w3.org/QA/Tips/reback

 

Copyright ©2007 Doug Danoff
Permalink | Trackback

Comments (10)  Add Comment
Re: The only thing to fear of the back button… is fear itself  By Steve.Morse on 3/11/2007
Are you saying that the response to EVERY post should be a brower redirect? Or that browser redirect should always be used instead of Server.Transfer()?

Re: The only thing to fear of the back button… is fear itself  By Doug.Danoff on 3/12/2007
Never show pages in response to POST
Always load pages using GET
Navigate from POST to GET using REDIRECT

I'm not against using Server.Transfer() in response to a get. And I'm not against using it in response to something where a the caller is looking for something other than a webpage. For example, some system call to fetch XML.

If the result of a post can be later accessed thru some browser navigation control, seriously consider using a redirect for it.

Re: The only thing to fear of the back button… is fear itself  By Dave.Sweeny on 3/12/2007
Agree that relying on user education, broswer disabling, and/or warnings is really skirting the issue. Using some form of tokens seems more effective, but also significantly more labor intensive.

Maybe include some snippets/pseudocode showing the PRG?

Re: The only thing to fear of the back button… is fear itself  By Doug.Danoff on 3/12/2007
Yeah, I didn't want to recreate the wheel... Michael Jouravlev covered the details pretty well here.

Re: The only thing to fear of the back button… is fear itself  By Steve.Morse on 3/12/2007
I'm still missing something relevant here. A common pattern is "post backs" to the same page as a user interacts with the page. For example, the page displays a list with details of a selected item below. When a user clicks a list item it posts back, and the page now displays the details below. This is standard .ASPX with "view state". Are you saying there is something wrong with this technique?

Re: The only thing to fear of the back button… is fear itself  By Doug.Danoff on 3/13/2007
See part 2:
http://www.strong-point.com/Blogs/tabid/87/EntryID/9/Default.aspx

http://www.creditworld.com.au/credit-cards.html  By Credit Cards Australia on 7/14/2008
Your blog is very informative. However, earning money and balance your credit cards is pretty hard task but your post and experienced serve and teach me how to handle and make it more simple and manageable.

Thanks for the tips… Best regards.

http://www.creditworld.com.au/credit-cards.html  By Credit Cards Australia on 7/14/2008
Your blog is very informative. However, earning money and balance your credit cards is pretty hard task but your post and experienced serve and teach me how to handle and make it more simple and manageable.

Thanks for the tips… Best regards.

Credit Cards Australia  By Credit Cards Australia on 8/1/2008
Your blog is very informative. However, earning money and balance your credit cards is pretty hard task but your post and experienced serve and teach me how to handle and make it more simple and manageable.

http://www.creditworld.com.au/credit-cards.html

Thanks for the tips… Best regards.

PRG pattern with ASP.NET?  By Vladimir Kelman on 8/29/2008
This is a very interesting article. You're saying,

"Never show pages in response to POST
Always load pages using GET
Navigate from POST to GET using REDIRECT"

In fact, on all job interviews for last 10 years I tried to describe the same thing as one of the main selling points for being hired :)
A painful question is: how to marry it with ASP.NET's POSBACK paradigm and design-time controls which, to my knowledge are designed around it? Do you know any articles about it? I was interested in this type of solutions for a long time and found several articles about "cross-page postback" but not one seems to answer the question.
That's the main reason I hate ASP.NET model (while I really like .NET platform by itself, to me it recently went ahead of a similar Java / JVM platform, despite the fact that .NET originally "stole" most ideas from Java.

Currently, people develop ASP.NET MVC model, but is there any acceptable way to use POST-REDIRECT-GET with a classic ASP.NET?


Your name:
Title:
Comment:
Add Comment  Cancel 
Contact Information

Strong Point Consulting LLC is located in Malden, MA.

Contact us via
Contact@strong-point.com
A Senior Technologist will respond promptly.


Privacy Statement  |  Terms Of UseCopyright 2007 Strong Point Consulting LLC