Static Web Apps SPA Handle 404 Page Not Found

Single Page Applications (SPA) handle the client-side routing or navigation of pages without the need to send a post back or request to the server hosting the application. To enable the client-side routing, applications build using React or Angular and others bundle the application for a single download of all the page resources. This bundle download allows the routing service to load the next view container and components when the user selects a new page, essentially loading a new route, without having to make a request. Depending on the size of the application, this approach can lead to initial slow load time on the browser.

ozkary lazy loading 404 errors

To address the initial slow load time, a build optimization can be done that can enable the loading of the content associated with a route to be done on demand, which requires a request be sent to the server. The optimization is handled by using a lazy loading approach, in which the route content is downloaded as an application chunk from the hosting environment. This means that instead of downloading the entire app during the initial download, only an index of URLs pointing to chunk files that are associated to the route is downloaded. This can also include chunk files for CSS, JS and even image downloads. As a route is loaded, the index lookup provides the URL of the chunk to download, thus making the app load faster. When another route is loaded, a new chunk is downloaded.

Client-Side vs Server-Side Routing

The client-side routing works as designed when the navigation operations are done normally by the user clicking on menu options or call-to-action buttons.  In some cases, a user may have to reload or refresh the web application. This action forces the browser to make a request to the server.  Once the request makes to the server, the server-side routing rules are applied. If the server routes definitions do not have a handler for all the routes defined on the client-side, the server fails to find the content that is requested and responds with an HTTP 404 error, which means that a page is not found.

By default, the server-side routing knows to always return the index page hosting the SPA.  This is usually mapped to the root of the domain or / path. However, when a user starts to navigate the app, the routes change to match a different path. For the server to be able to understand what to send back when this new path is loaded, we need to configure the server in a way that it knows to return the index page for all the routes, not just the root path. For Static Web Apps (SWA) which are hosted on CDN resources, this is done using a configuration setting for the application. These settings enable the configuration of the routing and security policy for the application. Let’s use an example to review that in more detail.

Static Web Apps Settings

Imagine that we have an SPA app with the following client-site route configuration:


The above routing information is typical of an app that has a home, about and contact page. The SPA provides the navigation elements or call-to-action buttons, so the user can select any of those pages.  When the user is on the home page which is defined by the home route or /, a page reload does not cause any problem as this path is usually associated to the index page of the application on the server routing configuration.

When the user navigates to the other route locations, for example /about, a page reloads sends a post back to the server, and if there is no handling for that page the 404 error is created. Depending on the hosting resource, the 404 page can be system generated, which takes the user away from the application experience altogether.

To manage this concern, the latest release of SWA provides the staticwepapps.config.json file. This file is required to be able to configure the server-side route and security information for the app. It is also used to override the behavior of some HTTP operations, as well as configuring HTTP responses. For the scope of this conversation, we focus on the routing configuration only.

Note: At the time of this writing, the routes.json file has been deprecated for the staticwebapps.config.json. The configuration between these files has some differences, so carefully review the options being used, just renaming routes.json will lead to problems on the application behavior.

Routing and Response Overrides

The routes' configuration enables us to add server-side routing rules with security, for authentication and authorization requirements, as well redirect rules for a request.  To avoid the 404 error, the SWA configuration should have an entry for every client-side route configuration. For our specific example, this means that we should add the routes for the /about and /contact-us route. This is done by adding route entries in the routes' collection, as shown below:


"routes": [


      "route": "/",

      "allowedRoles": ["anonymous"]

    }, {

      "route": "/about",

      "allowedRoles": ["anonymous"]

    },  {

      "route": "/contact-us",

      "allowedRoles": ["anonymous"]



The routes on the server-side configuration lists all the client-side configuration and add a security role to enable anonymous users to access the route.  

Do We Need to Map All the Routes?

We do not only if we use a fallback policy. Our routing configuration only has three separate routes, and thus it is simple to manage. This however is not reflective of a complex app which can have several route entries. In addition, having to add every single client-side entry on the server is error-prone, as a route can be configured improperly or just forgotten to be included.

The Static Web App team also figure as much, so a fallback setting was introduced on more recent releases. This setting allows the server configuration to “fallback” to the default route when a route is not defined. This works just as good because for SPA, we always want the index page to be sent to the client. As the page is loaded on the browsers, the SPA routing service identifies the route information and download the chunk files associated to the route. This fallback setting looks as follows:


"navigationFallback": {

    "rewrite": "index.html",

    "exclude": ["/images/*.{png,jpg,gif}", "/css/*"]




On the fallback setting, we should note that we are doing a rewrite operation instead of redirect. This is efficient because a rewrite is handled on the server, so there is no client-side trip and another request as the redirect operation creates.  We should also notice that we do not want to rewrite missing resources to the index page. To avoid this, we exclude all the images and CSS files. The order on how these settings is configured on the file is also relevant. Usually, the settings that come later on the document take precedence and override the previous settings. To help on this, we can look at a complete staticwepapps.config.json.

Are There Client-Side Page Not Found Errors?

Yes, there are these errors as well. These errors are different from an HTTP 404 error. These client-side errors indicate that there is some call-to-action element on the app that has a path with no routing configuration. This is not a server error, so there should also be a fallback to handle that problem on the client routing configuration. This is often done by creating a wildcard route entry as the last route step, so when a route is not found, it can load the page not found component.


SPA application routing is done on the client-side of the application, but when the user does an operation that can cause the SPA to bootstrap again, a server-side request is made. If the hosting environment web server, CDN do not have routing configuration or a fallback to handle new routes added to the client side, the hosting environment returns a 404-error page that takes the user completely out of the application. Therefore, it is important to add routing to both the client and server and manage route issues on both ends. This should help us guards against 404 page not found errors.

Have you experienced similar problems with your apps? 

Send question or comment at Twitter @ozkary

Originally published by ozkary.com


Post a Comment

What do you think?