I serve a Vue SPA from an Azure Web App. There is no server side logic (or none relevant to this problem anyway).
I am using Vue Router in HTML5 history mode. It works really well. The only problem is what happens when a user tries to access a view inside the app with a "direct" URL such as https://my.app.com/contacts. This gives a 404 Not Found, as expected.
The workaround is well known: use URL Rewriting to route such requests to the root of the app: / or /index.html.
So that's what I'm trying to do. For Azure Web Apps, the way to do it is using rewrite rules in a web.config file. My Web.config looks like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Handle History Mode and custom 404/500" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
This is lifted straight out of the documentation for Vue Router, here.
When I access the site now, I get a blank page. Using the developer console (in Chrome) and checking the network tab, I discover that all requests now return the content of index.html, including script files and css files.
So the rewriting clearly works, just a little too much.
The problem seems to be the (negated) IsFile and IsDirectory conditions. These use the REQUEST_FILENAME server variable. From this page I understand that this is supposed to be the mapped path on the server file system.
As all requests are rewritten, it must be because the conditions fail to recognize the paths as valid file or directory paths.
Edit:
I have used failed request tracing to debug the url rewriting, and have learned some more. It turns out that when the rewrite module runs, the REQUEST_FILENAME
variable is incorrect.
In the azure web app, the content root is at D:\site\wwwroot
. In this folder is my app's wwwroot folder. Some googling reveals that this is as expected. Also, the mapping works correctly - with no url rewriting enabled, an url path like /img/logo.png
will return the static file at D:\site\wwwroot\wwwroot\img\logo.png
.
But when the url rewrite module runs, REQUEST_FILENAME
will have the value D:\site\wwwroot\img\logo.png
. That file does not exist, and so the IsFile
condition fails.
The question is then: why does the url rewrite module and the static file provider disagree on the path mapping?