Skip to content

ServiceWorker doesn't update index.html when headers (e.g. CSP) change #37390

Closed as not planned

Description

@wibimaster

🐞 bug report

Affected Package

The issue is caused by package @angular/service-worker:9.1.7

Is this a regression?

Nope, seems to always been there

Description

Supposition: It seems that the service worker use body response only to generate its hash, corresponding to versioned resources ; update some headers server side doesn't update these hashes and resources are served with old headers.

🔬 Minimal Reproduction

When deploying Angular application with service-worker (default configuration):

  • Load the main page in a browser
  • Service worker do its job and cache resources (including index.html)
  • Change global resources header (in my case, nginx configuration, like add_header X-OneThing "hello there"
  • Let the service worker try to do a cache bust
  • Take a look on the answer : no update detected
  • Refresh the page : the new header isn't applied (but the ngsw.json HTTP call got it, of course)

Sorry but cannot do a stackblitz with that :/

🔥 Exception or Error

None

🌍 Your Environment

Angular Version:


> ng "version"


     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 9.1.6
Node: 12.14.1
OS: linux x64

Angular: 9.1.7
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.901.6
@angular-devkit/build-angular     0.901.6
@angular-devkit/build-optimizer   0.901.6
@angular-devkit/build-webpack     0.901.6
@angular-devkit/core              9.1.6
@angular-devkit/schematics        9.1.6
@angular/cli                      9.1.6
@angular/platform-server          9.1.9
@angular/service-worker           9.1.9
@ngtools/webpack                  9.1.6
@schematics/angular               9.1.6
@schematics/update                0.901.6
rxjs                              6.5.5
typescript                        3.8.3
webpack                           4.42.0

Activity

  1. added this to the needsTriage milestone on Jun 2, 2020
  2. gkalpak commented on Jun 2, 2020

    @gkalpak
    Member

    Thx for reporting this, @wibimaster. Can you please clarify what you mean by "Let the service worker trying to do a cache burst"?

  3. added
    needs reproductionThis issue needs a reproduction in order for the team to investigate further
    on Jun 2, 2020
  4. wibimaster commented on Jun 2, 2020

    @wibimaster
    Author

    @gkalpak
    Sure, I mean the HTTP calls to: /ngsw.json?ngsw-cache-bust=0.440594490857368

    I write a loop following the documentation to call this every five seconds, for testing purpose ;)

    const appIsStable$ = this.appRef.isStable.pipe(first(isStable => isStable === true));
    const msInterval$ = interval(5 * 1000);
    const everyMsIntervalOnceAppIsStable$ = concat(appIsStable$, msInterval$);
    everyMsIntervalOnceAppIsStable$.subscribe(() => this.swUpdate.checkForUpdate();
    
  5. gkalpak commented on Jun 2, 2020

    @gkalpak
    Member

    I see. In that case, the SW will not re-request the files and get the new headers. Since we are talking about hashed asset requests (i.e. requests for files that exist at build time, not some dynamically generated API request), the SW only cares about their content. Among other reasons, it is because it uses the content hash to ensure that a specific file version corresponds to an app version (as specified in the corresponding ngsw.json).

    What is your usecase? Why do you care about headers of static assets?

  6. wibimaster commented on Jun 2, 2020

    @wibimaster
    Author

    My specific use case is about CSP headers ; if I change them because of a bug, too strict, or whatever, the application is locked in a bad state...

    Not all static assets are concerned : mainly "index.html" because it loads main javascript files.
    A simple typo into CSP headers and JS are not loaded and the application will be broken if it's cached :/

  7. changed the title [-]Service worker doesn't use headers to generate hashes[/-] [+]ServiceWorker doesn't update `index.html` when headers (e.g. CSP) change[/+] on Jun 5, 2020
  8. gkalpak commented on Jun 5, 2020

    @gkalpak
    Member

    Oh, I see. That sounds like a valid usecase indeed.

    If it's only about index.html, we could change the ServiceWorker to always fetch ngsw.json > index from the server. If more files/URLs are affected, then I am not sure what would be a good solution/API.

    In the meantime, a work-around for index.html is to update its content in any way to make its hash different (e.g. add the current revision SHA in a comment or something).

  9. 15 remaining items

  10. Masinac commented on Dec 21, 2022

    @Masinac

    I'm currently experiencing the same problem.

  11. nthornton2010 commented on Sep 6, 2023

    @nthornton2010

    Same problem here too

  12. jspivack commented on Sep 21, 2023

    @jspivack

    Definitely still an issue

  13. pmachauxOrigin8Cares commented on Mar 21, 2024

    @pmachauxOrigin8Cares

    Still an issue

  14. cxyblood21 commented on Jul 12, 2024

    @cxyblood21

    Still having an issue with this as well. Any updates?

  15. edwinhilgersom commented on Aug 2, 2024

    @edwinhilgersom

    +1 also still experiencing this

  16. bhaskerchari commented on Aug 2, 2024

    @bhaskerchari

    Setting "navigationRequestStrategy": "freshness" in ngsw-config.json does help to set updated headers on index.html because on navigation request browser does contact server to fetch the latest file and thereby the headers get updated. Though it doesn't guarantee that the updated headers are set on the other static resources such as js, css etc

    But given its a SPA and index.html being the main document of the application it does resolve the issue.

  17. edwinhilgersom commented on Aug 5, 2024

    @edwinhilgersom

    Thanks for your response!

    Our workaround was to place a ?v=timestamp in the place we register the service worker module each time you want the CSP headers to be updated, plus a change in the index.html file.

    Also had to duplicate the CSP headers from img-src and frame-src in connect-src.

  18. janwidmer commented on Mar 12, 2025

    @janwidmer

    We are experiencing a similiar Issue:
    We run an Angular Website using Service Worker and a Content Security Policy. The policy is maintained in the cloud, where also the angular app runs. Therefore, we do not need a deployment to change something in the CSP.

    Imagine the following case:
    The customer who runs the website, wants to add an additional 3rd Party Script via Google Tag Manager. We enhance the CSP to contain the new domain for the new script.

    This works for full reloads without having the service worker already installed. When having the service worker already installed and doing a full reload, but also when navigating to the page via Angular navigation action, the error happens because the service worker seems to use an outdated CSP not containing the new domain:

    Image

    The blurred area in the image contains the CSP Values for the property connect-src WITHOUT the newly added domain.

    Basically the same issue as described here: #35491

    @dsm0880 with your guess about the Service Worker taking the CSP from ngsw-worker.js, how did you come to this guess? In our case, the file ngsw-worker.js is actually cached for a year and therefore the CSP sent with this file is very likely outdated. I guess, yo do not have any documentation about how that actually works?

    @gkalpak As you see in my example, there is no deployment happening, but the CSP can still change. How do the browsers handle a Cached SW Script without having a deployment, is the Script still only cached 24 hours (as you explained above) or how is the cache life time of the SW Script defined?

    Which CSP is the Service Worker actually using when doing requests? (The one delivered on the index.html request or the one delivered on ngsw-worker.js)

    @edwinhilgersom I guess your solution only works when the CSP Change happens at the same time as also a deploment is done, correct?

  19. montella1507 commented on May 19, 2025

    @montella1507

    So there is no way how to use CSP when service-worker is active...

    Because:

    1. Hash of index.html is stored inside ngsw.json, build time.
    2. index.html is changed with EVERY request as far as you need to replace placeholder for CSP_NONCE on the root element
    3. hash mismatch

    => Service worker will not activate new version, because he was not able to download index.html with correct hash.....

    BTW i dont see any code regardging CSP nonce in the worker...
    https://github.com/angular/service-worker-builds/blob/main/ngsw-worker.js

    And you cannot exclude index.html from ngsw because application WILL NOT be able to work offline...

    I see only one possible solution to modify service-worker.js to read response headers - read CSP nonce... reaplce in in memory in index.html file and calculate hash in memory version (with original "placeholder" for nonce)

  20. JeanMeche commented on Aug 29, 2025

    @JeanMeche
    Member

    With #63364 we've announced that the service-worker package in now in maintenance mode and will not receive feature PRs and feature requests.

    The message is also visible here: https://angular.dev/ecosystem/service-workers

  21. angular-automatic-lock-bot commented on Sep 29, 2025

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  22. locked and limited conversation to collaborators on Sep 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions