60% of Web Users Can’t be Wrong – Don’t Break the Back Button!
October 3, 2007 in HTTP
Usability studies have shown that 60% of users rely on the back button as their primary means of navigating around the web (source: Usability Interface). In fact, several studies have shown that the back button is second only to clicking on links as the most used feature on the web (source: Web Usability research). So why do so many sites ignore the back button and frustrate users who try to use it on their web site?
The problem stems from the fact that many web sites display an HTML page in direct response to a POST method method initiated by a <form>
submit. Whilst this is quite common it can exhibit a number of issues in some scenarios.
The first problem is that attempting to refresh the results page causes this dialog to be displayed:
Of course, web users never read anything so they will randomly click on Cancel or Retry! If they click on Cancel nothing happens. If they click on Retry they will see a refreshed version of the page but there’s a danger that an operation could be duplicated (e.g. moving money between accounts).
A second and more frustrating issue that everyone will be familiar with is the broken back button. When the user tries to navigate back to a page returned from a POST it may cause the following message:
These problems don’t exist if the form element uses the GET method with the form variables appended to the URL as a query string. This is because the HTTP specification mandates that GET requests should always return the same response for a given query string and have no side effects. Operations such as this are said to be idempotent and can be safely repeated without user confirmation.
Unfortunately, GET can’t be used in every case. If the query string exceeds 4 KB or the operation is not idempotent then POST must be used. A good example of an action being performed in response to a POST would be a money transfer. The resulting page would show the current balance and it would be different each time the POST action was performed.
The ‘webpage has expired message’ only occurs with if the page has been configured to protect private data as shown here using HttpWatch:
The header Cache-Control: no-cache
is crucial to secure web sites such as online banking or credit card sites to prevent user data accidentally being exposed to other users by intermediate proxies, or by the browser’s cache or history list. It prevents any storage of the page and forces the browser to issue requests to the web server whenever the page is re-displayed. The added benefit of this header is that it prevents stale data (e.g. account balance) being displayed when an old page is re-opened in the browser.
When a secure page like this is returned from a POST, it cannot be automatically redisplayed if the user navigates to it using the Back button. The browser will attempt to reload the page from the history list, but nothing is stored because of the no-cache
setting. It then checks to see if it could safely re-issue the request that originally returned the page from the server. In the case of a POST request that could result in the undesirable consequences of performing the same action twice. So, the browser plays it safe and displays the ‘webpage has expired’.
The solution to these problems is to display HTML pages only in response to a GET and to always redirect POST requests. The resulting pages can be safely refreshed or revisited without the annoying messages and without causing the POST action to be accidentally duplicated. If necessary, the browser can automatically re-issue GET requests without prompting the user because there will be no side effects.
This technique is known as the POST/Redirect/GET (PRG) pattern and according to Michael Jouravlev it is characterized by the following guidelines:
- Never show pages in response to a POST
- Always load using GET
- Navigate from POST to GET using Redirect
Using HttpWatch we can see PRG in action on a different site:
The server issues a 302 status code along with a new URL. The browser takes this to mean that all references to the POST URL should be temporarily redirected to the new URL using the GET method. Notice that rendering the page incurs an extra HTTP round-trip to the server, but the browser’s forward, back and refresh buttons will now work as expected. The overhead of the extra round-trip is usually negligible compared to the overhead of downloading the page and its embedded images.
So that’s the PRG pattern. If you’ve got any questions about this or HttpWatch you can reach as at feedback@simtec.ltd.uk.