dotnet / dotnet/aspnetcore

[Validation] PWA service worker when the start page is reached through a redirect

Open
#68,535 2 comments 0 reactions 1 assignee Claimed by @karmegams02 View on GitHub
area-blazor Validation validation-scenario
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 10h
Merged PRs (30d)
281

Description

**Scenario contact:** @javiercn

## Scenario

**This scenario validates that a reported bug is fixed.** An app installed as a progressive web app is expected to open and work without a network connection, which is most of the reason for installing it. On hosts that redirect the request for the app's start page, the cached response carried a redirect flag that browsers refuse to replay, and the service worker failed with:

> The FetchEvent for "/" resulted in a network error response: a redirected response was used for a request whose redirect mode is not "follow".

The app worked on the **first** visit and then showed the browser's error page on every visit after that, online or offline, before any of the app's own code ran. Cloudflare Pages was the reported host, but any host that redirects to the start page hits it. ([#33872](https://github.com/dotnet/aspnetcore/issues/33872))

This validates that an installed app starts and keeps working, including when what it cached was reached through a redirect.

## Minimum build

.NET 11 Preview 7 or later.

## Configurations to cover

* Blazor Web App
* [ ] Static SSR
* [ ] Interactive Server
* [ ] Interactive WebAssembly
* [ ] Interactive Auto
* [x] Standalone WebAssembly
* [ ] Hybrid (MAUI)

## Also exercise

* [x] Published output
* [x] An existing .NET 10 app upgraded to .NET 11
* [ ] Trimming or ahead-of-time compilation
* [ ] More than one server instance, or a proxy in front
* [ ] Hot Reload
* [ ] An IDE as well as the command line
* [ ] Container

## Setup

Create the app with progressive web app support included, and publish it. Offline support only exists in published output, because the development service worker deliberately does nothing.

```bash
dotnet new blazorwasm -n PwaRedirectTest --pwa
cd PwaRedirectTest
dotnet publish -c Release
```

You then need to serve the published output from a host that **redirects `/index.html` to `/`**. That is the canonicalisation Cloudflare Pages performs, and it is what triggers the bug: the service worker fetches `index.html` while installing, follows the redirect, and caches a response carrying the redirect flag.

### A local server that reproduces it

Any server that can do that redirect will do. The following examples use nginx with the following configuration saved as `pwa.conf`:

```nginx
events {}
http {
include mime.types;
server {
listen 8080;
root /absolute/path/to/publish/wwwroot;
location = /index.html { return 301 /; }
location / { try_files $uri /index.html =404; }
}
}
```

Run it with:

```bash
nginx -c /absolute/path/to/pwa.conf
```

Two notes to avoid infinite redirect loop:

* `root` and the `-c` path must be **absolute**. On Windows use forward slashes, for example `C:/src/PwaRedirectTest/bin/Release/net11.0/publish/wwwroot`.
* In `try_files $uri /index.html =404`, the `/index.html` must **not** be the last parameter. As written it is a file lookup served directly. If you write the more familiar `try_files $uri $uri/ /index.html;` instead, the fallback becomes an internal redirect that re-enters `location = /index.html`, and every request including `/` returns 301 forever.

Confirm the setup before you start, otherwise nothing you observe means anything:

```bash
curl -I http://localhost:8080/index.html # expect 301, Location: /
curl -I http://localhost:8080/ # expect 200, Content-Type: text/html
```

`localhost` counts as a secure context, so service workers and installation work over plain HTTP with no certificate. `mime.types` in current nginx already maps `.wasm` to `application/wasm`, which WebAssembly startup needs.

The fix lives in `wwwroot/service-worker.published.js`, which is a template file rather than framework code. An app upgraded from .NET 10 keeps its old copy and stays broken until that file is updated, so if you test the upgrade path, check what the file contains before concluding anything.

## What to build

The app the template generates is enough. Add a second page and a stylesheet so there is something to navigate to and something visible to load from the cache. Publish it, serve it through the redirecting server above, then visit and install it.

## Things to try

* Visiting the app, then **reloading the page while still online**. This is where the old failure appeared, on the second visit rather than the first.
* Watching the browser console for `a redirected response was used for a request whose redirect mode is not "follow"`.
* Installing it, closing it, and reopening it from the operating system.
* Going offline and opening the installed app from the operating system.
* Going offline and reloading the app in a browser tab.
* Navigating between pages while offline.
* Coming back online, publishing a changed version, and confirming the installed app picks it up.
* An app upgraded from .NET 10 whose `service-worker.published.js` still has the old contents, to see the failure this fixes.
* Repeating in a second browser.

## Expected behavior

The app keeps working after the first visit, whether it is online or offline, and whether or not the address redirected.

### Must hold

* `curl -I http://localhost:8080/index.html` returns `301` with `Location: /`, confirming the setup actually reproduces the redirecting host. Without this the rest proves nothing.
* Reloading the app while online serves the app, not the browser's error page.
* No console message about a redirected response being used for a request whose redirect mode is not `follow`.
* With the network off, the installed app opens from the operating system and works.
* With the network off, reloading the app in a browser tab still serves it.
* Pages, images and stylesheets all load from the cache while offline, with no failed request in the network log.
* Coming back online lets the app pick up a newer published version.

### Expected differences between configurations

* No differences are expected between browsers. If one browser serves the app and another shows an error page, that is a finding.

## Evidence to capture

The browser network log for a full offline load, showing which requests were served from the cache, and a screenshot of the running app with the network confirmed off. If anything failed, the console message in full.

## Documentation to use

* [Build Progressive Web Applications with ASP.NET Core Blazor WebAssembly](https://learn.microsoft.com/aspnet/core/blazor/progressive-web-app/?view=aspnetcore-11.0)
* [Using Service Workers on MDN](https://developer.mozilla.org/docs/Web/API/Service_Worker_API/Using_Service_Workers)

## What to report

Report results using the format described in the [validation testing manual](https://github.com/dotnet/aspnetcore/issues/68479). Include link to a repository with the test app.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.