angular icon indicating copy to clipboard operation
angular copied to clipboard

Service Worker 504 Gateway Timeout for external resources

Open zerefel opened this issue 1 year ago • 12 comments

Which @angular/* package(s) are the source of the bug?

service-worker

Is this a regression?

No

Description

The fetch call for external resources, such as analytics scripts, ad manager scripts or styles will always fail when invoked after the service worker has been initialized. It appears that this is true for all opaque responses, where one can't control the CORS configuration.

I've deployed a fresh Angular 17 app generated with the CLI on Cloud Run. The only modification I've done is add the Google Analytics script to index.html. Note that there is nothing special about this script, it will fail the same way for any other external resource. Repo that's in-sync with the deployed app: https://github.com/zerefel/angular-sw-fetch

Reproduction steps

  • Load the app for the first time or hit Ctrl + Shift + R -> The analytics script will be loaded successfully.
  • Refresh the page (Ctrl + R) -> The analytics script can't be loaded.

I've been testing with various ngsw-config.json setups, tried to configure it with dataGroups, I also went through pretty much every single related issue, read the service worker documentation multiple times, nothing seems to help, so I can only assume this is a bug.

Expected behavior

The service worker manages to load the resources, or at least give a meaningful error message.

Please provide a link to a minimal reproduction of the bug

https://angular-sw-test-ccqkuvfrra-nw.a.run.app

Please provide the exception or error you saw

TypeError: Failed to fetch
    at Driver.safeFetch (ngsw-worker.js:1832:33)

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 17.0.6
Node: 20.9.0
Package Manager: npm 10.1.0
OS: linux x64

Angular: 17.0.6
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, platform-server
... router, service-worker, ssr

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1700.6
@angular-devkit/build-angular   17.0.6
@angular-devkit/core            17.0.6
@angular-devkit/schematics      17.0.6
@schematics/angular             17.0.6
rxjs                            7.8.1
typescript                      5.2.2
zone.js                         0.14.2

Anything else?

Due to the nature of some dependencies, which request an arbitrary number of scripts of their own, (e.g. ad manager scripts), it is not viable to list every single URL in the dataGroups config, as they may not be known or could dynamically change.

zerefel avatar Dec 07 '23 23:12 zerefel

Experiencing the same issue on v17 (in our case it is failing to fetch from the google recaptcha api). Has anyone found a workaround?

joewIST avatar Jan 18 '24 11:01 joewIST

@zerefel Are you running an ad blocker extension by chance?

The request in your example app was showing up as a 301 script/redirect via my ad blocker on first load. The next load it was a 504 (I'm assuming due to the service worker caching the extension redirect response). I disabled my ad blocker and then it seemed to work even after multiple reloads.

first load with ad blocker

Screenshot 2024-01-18 at 4 34 28 PM

subsequent loads with ad blocker

Screenshot 2024-01-18 at 4 34 55 PM

loads without ad blocker

Screenshot 2024-01-18 at 4 35 37 PM

huwyca avatar Jan 18 '24 21:01 huwyca

@huwyca I was using Brave browser to test, which has a ton of built-in privacy/blocking features. Even with all extensions disabled it would still return a 504. However, I can confirm that it works as expected in Chrome with AdBlock extensions disabled. I think it's a browser issue after all.

@joewIST can you provide any additional information, if not I'll go ahead and close this issue.

zerefel avatar Jan 22 '24 12:01 zerefel

We are using a library for adding recaptcha to certain API calls, and this is frequently getting blocked with 504 errors. The issue seems to be that something is preventing the browser from downloading the package files, which is causing issues with logging in.

joewIST avatar Jan 22 '24 14:01 joewIST

The same here, someone was able to get a workaround for this problem?

nandowalter-lm avatar Mar 06 '24 15:03 nandowalter-lm

This drag so much my SEO point and customer complain about it, I dont notice this issue since safari seem not cache, only chromium using some kind of cache and this issue happen

hiepxanh avatar Mar 06 '24 15:03 hiepxanh

I'm experiencing this bug in macOS Safari 17.3.1 but also it occurs on iOS Safari 17.4.

iOS 17.4 👇 image image

I'm trying to avoid service worker fetch intercept for some specific resource path, in this way the problem seems to be temporary solved. This is not an ideal solution and I would like to understand what's the cause. this is an example for makes gtm.js bypass sw:

self.addEventListener('fetch', event => {
    if (event?.request?.url.includes('/gtm.js')) {
        event.stopImmediatePropagation();
    }
});

importScripts('./ngsw-worker.js');

Using this workaround I was able to get gtm.js loaded as expected: iOS 17.4 👇 image

I was inspired by this dev.to post

This is a serious trouble, is anyone from Angular team aware of this?

nandowalter-lm avatar Mar 07 '24 07:03 nandowalter-lm

I think there is some issue with new build system esbuild or angular 17, I'm not having this issue with angular 16

hiepxanh avatar Mar 15 '24 14:03 hiepxanh

I'm seeing the same issue, any calls to an external resource are being blocked with a 504 by the Service Worker with an error message similar to the following:

Refused to connect to 'https://cdn.appdynamics.com/adrum-ext.8ad16b8375327e66a32816a8ad7be617.js' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.

or

Refused to connect to 'https://www.google-analytics.com/g/collect?v=2&...etc...' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.

Because these are external resources, we have no control over the CORS configuration and there is no way to add an ngsw-bypass header or query param. The requests also don't go through the angular HttpClient so we can't modify the request with an HttpInterceptor.

I've also tried adding a <meta http-equiv="Content-Security-Policy" content="connect-src *;"/> tag in the index.html but that doesn't seem to do anything.

thecheeto avatar May 09 '24 17:05 thecheeto

I have done 2 things to successfully work around the 504 error. I've defined an assetGroup within ngsw-config.json explicitly listing the external URLs,
e.g.,

{
      "name": "external",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "urls": [
          "https://www.googletagmanager.com/gtm.js",
          "https://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js",
          "https://images.ctfassets.net/das9i29csy1d/**/*.jpg"
        ]
      }
    },

and more importantly I've updated my CORS connect-src URL list with all the external URLs, which is needed to allow the service-workers fetch requests.
e.g.,

connect-src 'self' stats.g.doubleclick.net *.google-analytics.com *.googletagmanager.com *.googleapis.com *.gstatic.com images.ctfassets.net;

bmerigan avatar May 09 '24 23:05 bmerigan

@bmerigan where have you updated the CORS connect-src URL list?

Is that in a meta tag like <meta http-equiv="Content-Security-Policy" ... or somewhere else?

thecheeto avatar May 09 '24 23:05 thecheeto

@thecheeto It's in my nginx config, which is basically the server config where my application runs. I don't think you'd have much success putting it in the HTML file.

bmerigan avatar May 10 '24 01:05 bmerigan