flutteriis-8production

404 - File or directory not found in a production web application (where includeHash is set to false)


In my current development, in debug mode, I noticed a URL address every time I ran my web application in Chrome: http://localhost:1111/#/my_app (for illustration purposes only).

To address this, I found a solution:

import 'package:flutter/material.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';

void main() {
  setUrlStrategy(PathUrlStrategy());
  runApp(MyApp());
}

And this thread to use flutter_web_plugins: This package does not have flutter_web_plugins in the dependencies section of pubspec.yaml.

I found out that by including the PathUrlStrategy() function, it will set includeHash = false as its default configuration.

I need to retain this code to eliminate the hash in the URL link to my web application.

Here are the detailed steps to reproduce:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <staticContent>
            <mimeMap fileExtension=".arb" mimeType="application/json" />
            <mimeMap fileExtension=".frag" mimeType="text/plain" />
            <mimeMap fileExtension=".wasm" mimeType="application/wasm" />
            <mimeMap fileExtension=".env" mimeType="text/plain" />
            <mimeMap fileExtension=".symbols" mimeType="text/plain" />
            <mimeMap fileExtension=".last_build_id" mimeType="text/plain" />
        </staticContent>
    </system.webServer>
</configuration>

iis_manager

404-not-found

What should I do if I need to eliminate the hash in the URL address of my web application in production, but it seems this introduces the 404 error?


Solution

  • I resolved it through a workaround. Firstly, I downloaded the URL Rewrite Module 2.1 English: x64 installer since it works with: IIS 7, IIS 7.5, IIS 8, IIS 8.5, IIS 10, and my IIS is version 8.5.

    Secondly, I refactored web.config file configurations:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <system.webServer>
            <httpErrors errorMode="Detailed" />
            <asp scriptErrorSentToBrowser="true" />
            <rewrite>
                <rules>
                    <rule name="Flutter Deeplinking" 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="/index.html" />
                    </rule>
                </rules>
            </rewrite>
            
            <staticContent>
                <mimeMap fileExtension=".arb" mimeType="application/json" />
                <mimeMap fileExtension=".frag" mimeType="text/plain" />
                <mimeMap fileExtension=".wasm" mimeType="application/wasm" />
                <mimeMap fileExtension=".env" mimeType="text/plain" />
                <mimeMap fileExtension=".symbols" mimeType="text/plain" />
                <mimeMap fileExtension=".last_build_id" mimeType="text/plain" />
            </staticContent>
        </system.webServer>
    </configuration>
    

    I need to see the specific issue with the web app, so I decided to include these tags (optional):

    <httpErrors errorMode="Detailed" />
    <asp scriptErrorSentToBrowser="true" />
    

    Since in my testing, the web app's initial load uses https://testdomain.com/#/my_app (with the hash), then eventually removes it (i.e., https://testdomain.com/my_app) once loaded. Therefore, I've included the following configuration:

    <rewrite>
        <rules>
            <rule name="Flutter Deeplinking" 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="/index.html" />
            </rule>
        </rules>
    </rewrite>
    

    My understanding of the code configuration above is that it ensures index.html is served upon a client request. This allows the web app to properly access the index.html default page. This happens when requesting the expected URL address, specifically https://testdomain.com/my_app. The primary purpose of the given configuration is to correctly handle requests for the hash-less URL address.

    Important Notes

    Aside from the 404 error, I also encountered and resolved a 500.19 error during troubleshooting. I found that the URL Rewrite module was not working properly. To fix this, I needed to repair the module by locating the rewrite_amd64_en-US.msi file and double-clicking it. This launched the IIS URL Rewrite Module 2 Setup wizard, where I clicked the REPAIR button. After that, I ran iisreset in the command prompt to restart the IIS manager.

    Fortunately, my web app is now working even if I reload the page (i.e., by pressing F5 or clicking the reload icon of the browser).