Stale Links and the Browser Back Button

The fact that web browsers have a "back" button is infuriating to application developers. What right does the user have to dictate the order of navigation through the application? Whose application is this anyway?

In a truly stateless application, the browser back button is not a great hardship, because each page carrys within itself (as cookies, hidden form fields and encoded URLs) all the state necessary to process the page.

Tapestry applications can be more stateful, which is a blessing and a curse. The blessing is that the Tapestry application, running on the server, can maintain state in terms of business objects, data from databases, Enterprise JavaBeans and more. The curse is that a user hitting the back button on the browser loses synchronization with that state.

Let's use an e-commerce example. A user is browsing a list of available cameras from a product catalog. The user clicks on a Minolta camera and is presented with pictures, prices and details about the Minolta camera.

Part of the page lists similar or related items. The user clicks on the name of a similar Nikon camera and is shown the pictures, prices and details of the Nikon camera. The user then hits the browser back button, returning to the page showing the Minolta camera, and clicks the "add to shopping cart" button. Web browsers have no way of informing the server that the user has employed the back button.

Once the user clicks the link, the server replies with a response showing the contents of the shopping cart ... but what has been added to the cart, the Minolta or the Nikon? It depends on how the Tapestry application has been structured.

Presumably, the application has a single page, named ProductDetails, that shows the pictures, prices and details of any product. The ProductDetails page will have a persistent property named product, of type Product. Product is a business class that contains all that pricing and detail information.

The question is, how is the add to shopping cart link implemented? If its logic is to add whatever the current value of the product property is (i.e., by using an ActionLink component or part of a form) then it will add the Nikon camera, since that's the current product (the most recent one displayed to the user, as far as the server is concerned ― it has no way to know the user hit the back button and was staring at the Minolta when the link was clicked). This is the natural approach, since it doesn't take into account the possiblility that the user worked backwards to a prior page.

On the other hand, if a DirectLink component is used, it can encode into the URL the primary key of the Minolta product, and that will be the product added to the shopping cart, regardless of the current value of the product property.

HTML Forms, controlled by the Form component, are also susceptible to these issues related to the browser back button. Still, there are techniques to make even forms safe. Borrowing an idea from more traditional JavaServer Pages development, a hidden field can be included in the form to sychronize the form and the application ... for example, including the primary key of the Minolta or Nikon product. Tapestry includes a Hidden component used for just this purpose.

Finally, the ListEdit component exists to help. It works like a Foreach, but encodes the number and value of the items it iterates as hidden form fields.