Hosting a Single Page Application (SPA) from Azure Blob Storage that supports deep links

Using Azure Blob storage to host static website files has been around for many years, it’s cheap, effective and fast to setup. It gives you the ability to effectively create a directory with a unique public URL that you can upload your static files to and have them hosted (no need for any web server). Microsoft has great documentation available that steps you through how to do this:

Static website hosting in Azure Storage

Tutorial: Host a static website on Blob Storage

This works well if your static website files are a bunch of html files (that contain links to each other to provide navigation). One scenario in which the Azure Blob Storage approach falters however, is if you try to host Single Page Applications (SPAs) in Blob Storage. Some aspects of the URL routing doesn’t work as you would expect for a SPA.

First let’s take a look at how URLs are designed to work in a SPA. Fundamentally there is only one page, hence the name SINGLE Page Applications! It is JavaScript running on that single page that is responsible for reconstructing the contents on that single page as the user ‘navigates’ around the application. So for this to work the browser doesn’t actually go back to the server requesting a new page so you would logically think that the URL at the top of your browser window would never change. Well, that’s not quite true, modern browsers understand SPAs and they allow SPAs to push a URL into the browser history and change the current location URL without causing a server request. Internally the SPA uses the concept of defining URL routes and handles any URL location beneath the root URL of the SPA. This makes it much easier for a user to understand where they are as they navigate through a SPA, and also provides support for native browser back and forward actions.

Example of a SPA

Only one file hosted on the web server called my-spa.html

The URL of this file is https://myserver/my-spa/index.html

Internally the SPA may defines 2 routes /page1 and /page2

When the user clicks on a link on the https://myserver/my-spa.html page the SPA tells the browser it’s changing the location to https://myserver/my-spa/page1 and the SPA changes some or all of the current page content. When you look at that URL though you should notice it points to a page that doesn’t physically exist on the server, https://myserver/my-spa/page1 isn’t a file you can go find on that webserver. Up until this point our Azure Blob Storage works as you would expect, because our modern browsers understand the SPA is routing internally and no request is sent to the server. There are two scenarios though that will break Azure Blob Storage.

Breaking Scenario 1 – Browser Refresh

What if we have https://myserver/my-spa/page1 URL in our browser and we hit the refresh button? This time our browser will make a request to the server and https://myserver/my-spa/page1 isn’t a file that exists so we will get a page not found error. Well that’s pretty crap you might think, these SPAs aren’t robust. There’s usually a little magic that goes on the server side when you host a SPA, you effectively rewrite/redirect all URLs https://myserver/my-spa/* to https://myserver/my-spa.html so that the SPA page handles all the URLs, it starts up, looks at the incoming URL and then it tries to match one of it’s internal routes and modifies the contents of the page to show content just as it would if the user started the SPA at the root URL and then navigated to that route.

Breaking Scenario 2 – Deep Links

A similar problem is a user trying to open a deep link into the SPA. Let’s say that a user was navigating through the SPA and arrived successfully at route that was displaying https://myserver/my-spa/page1 in the browser location. The user might copy/paste this link and send it to someone else (or just bookmark it and try to use it later). When someone tries to use that deep link (I call it a deep link because it’s trying to go someone in the SPA that isn’t the root URL) we fall into the same issue as the refresh situation, we are asking the webserver for a file that doesn’t exist. Again SPAs rely on the webserver having a URL rewrite/redirect or similar in place to ensure all URLs load that root https://myserver/my-spa.html file.

The Azure Blob Storage Problem – No Redirect/Rewrite Rules Possible

Unfortunately when hosting a static website using Azure Blob Storage we don’t get any facility to do that server side rewrite or redirection that would make it respond with the https://myserver/my-spa.html file. That’s one of the reasons that Azure later came up with an offering called Azure Static Web Apps, this is a different type of resource in Azure that is designed specifically for hosting static web apps and does overcome this server side URL rewrite issue. If you are creating a brand new site and have to ability to change your Azure architecture to use an Azure Static Web App rather than Azure Blob Storage then I’d suggest it might be your better option.

The Solution – Using Hash Location Strategy

There is a way to get your SPA working however with Azure Blob Storage, the solution is to change the way you construct your URLs to use something called a hash location strategy. This was actually a pattern to overcome a different issue, the issue of older browsers not knowing about SPAs and always sending server requests when the SPA wanted to navigate to one of it’s routes (e.g. from https://myserver/my-spa.html to https://myserver/my-spa/page1). Something browsers have understood for decades is the concept of a a inter-page anchor link, these are links to another section of the same page and the browser understands this by using # in the URL. The format is https://myserver/my-spa.html#anchor-name. If you design your SPA to do it’s internally routing using # instead of a URL path then you can see that our route that was generating a URL of https://myserver/my-spa/page1 could now generate a URL of https://myserver/my-spa.html#page1. Like magic this is now a file our Azure Blob Storage can find, when it loads the root SPA page our SPA now looks at the URL interprets what comes after the # as the route and works in much the same way it used to.

If you are using a framework such as Angular then switching to use a hash location strategy may be a simple thing to do. In the case Angular it’s a simple router property useHash=true

Sample of hash location strategy from the Angular.io tutorial

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Create a website or blog at WordPress.com

Up ↑

%d bloggers like this: