How to configure CloudFront for the HTML5 history API

Fix refresh 404 errors after using history.pushState

Author's image
Tamás Sallai
4 mins

Modern web applications handle their navigation state internally and don't require page reloads when the user is moving between the pages. This is a convenient feature as that also means ephemeral state, such as text entered into input fields and popups are preserved. But that also means, by default, that the URL that the users see stays the same and if they choose to reload the page they are taken back to the home page.

One solution for both of these problems was the use of fragments. This is the part that comes after the # and the webapp is free to change it and that does not cause a page reload.

// url is: example.com
window.location.hash = "articles";
// url is: example.com/#articles

And if the user reloads the page, the webapp can restore the navigation by reading the fragment:

// url is: example.com/#articles
window.location.hash; // #articles

This was the de-facto solution before HTML5 History API. The problem with fragments is that they are different. Instead of having a "normal-looking" URL, such as example.com/articles, it is example.com/#articles. Other than that, the browser does not send the fragment, so there is no way to provide useful data for clients that don't execute Javascript, such as web crawlers.

HTML5 History API

The History API provides a solution for all the problems with fragments and it is widely supported in browsers. It provides a pushState that changes the URL in a way that does not trigger a page reload.

// url is: example.com
history.pushState(undefined, undefined, "/articles")
// url is: example.com/articles

But it also introduced a new problem: what happens if the user reloads the page?

With fragments, the HTTP request goes to the same URL for all pages. But with pushState, it's no longer the case. Worse still, if the backend can not serve a HTML page for the changed URLs it's not immediately apparent.

Here's a video showing the problem: