Streamline Your Web App: Pretty URLs vs Server Round Trips

This article explores how to optimize web application performance by replacing traditional JSF navigation patterns with pretty URLs. By moving from standard JSF URLs to more semantic ones, developers can reduce server round trips, improve scalability, and enhance user experience. The solution involves shifting state management from backing beans to URLs using frameworks like PrettyFaces, resulting in bookmark-able, SEO-friendly URLs while eliminating session storage issues and simplifying navigation patterns. This approach works across JSF versions 1.1, 1.2, and 2.0, offering a robust solution for modern web applications.

3 Minutes reading time

Behold the masterpiece that AI hallucinated while reading this post:

"The Little URL That Could: How Pretty Links Made the Web App Zoom"

(after I fed it way too many marketing blogs and memes)

Created using DALL-E 3

AI-Generated: The Little URL That Could: How Pretty Links Made the Web App Zoom

Problem

Unnecessary server round trips are a common cause for slow application performance. Unfortunately application frameworks like JSF(Java Server Faces) are forcing developers to do so. For instance given the following URL processed by a JSF Implementation:

http://localhost/myapplication/customer.faces This shows us a customer edit form. We can navigate to other customers, edit a customer or delete the record. So where are the unnecessary round trips to avoid? Let’s take a closer look what happens in case of a JSF navigation rule to be fired. Given is a h:commandLink on the page causing a HTTP postback:

  1. HTTP postback is fired to the server

  2. During Invoke Application Phase, the action method is called giving an outcome.

  3. The outcome is processed by by the NavigationHandler, selecting the NavigationCase

  4. The new view is parsed

  5. During render response phase, the new HTML view is rendered and send to the browser

This is the standard request-response pattern known from HTTP protocol and the JSF life cycle. But what happens if we mark the navigation case as redirect? Then we will see the following:

  1. HTTP Postback is fired to the server

  2. During Ivoke Application Phase, the action method is called giving an outcome.

  3. The outcome is processed by by the NavigationHandler, selecting the NavigationCase

  4. A redirect is sent to the browser

  5. A HTTP Request is fired to the server with the new URL6. Render response phases is invoked

  6. During render response phase, the new HTML view is rendered and send to the browser

Here there are two server round trips, just to display one new page. This is not good as it slows down the application. But how to avoid?

Solution

Use pretty URLs, so instead of using standard JSF:

http://localhost/myapplication/customer/1344 http://localhost/myapplication/customer/4343 http://localhost/myapplication/customer/new This can be easily done by JSF and Frameworks like PrettyFaces with JSF 1.1, JSF 1.2 and also JSF 2.0! Give every customer it’s unique URL. This will generate bookmark-able, user-friendly, search engine parse-able URLs, and even the page refresh problem is no problem anymore. And navigating from one customer to another is pretty easy, as they are just links in the browser. Only one request-response is needed, and not two to get the right URL. Most of the JSF navigation rules will become obsolete.

The key point is to move state holding from backing bean to the URL. So instead storing the id of the current customer in a session scoped backing bean(which will cause problems with multiple opened browser windows), or storing the customer id in a request scoped backing bean and using the t:saveState component from Apache Tomahawk to create a “view scope”, we store the id in the URL and pass it during request processing using PrettyFaces. One nice side effect of this solution is that it makes the application more scalable, as no session stored values are used at all. The problem with JSF 2.0 View Scope or pre JSF 2.0 t:saveState is that it stores the backing bean value in the UIViewRoot, which itself is stored inside the current session. This can be avoiding by just using request scoped backing beans together with pretty URLs, and no session data at all.

Nice, right?

Git revision: 2e692ad