Non-CORS requests from DevTools can pollute the cache
See original GitHub issueLibrary Affected: workbox v5.1.3 npm
Browser & Platform: Google Chrome v85
Issue or Feature Request Description:
CORS requests from known CDNs like “fonts.googleapis.com” o “cdn.jsdelivr.net” often fail, but are cached correctly as cors
.
On Chrome the errors can be triggered by toggling the development panel and reloading the page. But can happen for other unknown reasons too. On Firefox the issue still occurs, in different conditions, and can even affect the page’s look (when “normalize.css” goes missing for example)
It happens on different machines under different networks.
I’ve made a minimal reproducible example, you can try it on pages. Open the console and see.
Recap of what said here:
-
observation 1: when reloading the page, only three requests are logged: for the stylesheet, the main js file, and the favicon.
No html file. Is this expected? I thought the http cache affected workbox’sfetch
es, not the entire event capturing. -
observation 2:
after the developer tools have been opened (Ctrl+shift+i):- the first page reload will trigger all the requests again, and the cors error will always occur.
- the second page reload will trigger all the requests again, no error messages will be print.
- the subsequent page reloads will show the same three requests mentioned above
after the developer tools have been closed:
- the first page reload will trigger all the requests again, no error messages will be print.
- the subsequent page reloads will show the same three requests mentioned above
Looks like opening the dev tools alters some caching mechanism. It temporarily breaks cors requests too. Not sure why the error persisted between reloads in my previous tests, might have been because I was toggling the dev panel.
I’ve ran the app in Firefox, to see if I could gather something more. It says:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://cdn.jsdelivr.net/npm/normalize.css@8/normalize.min.css. (Reason: CORS request did not succeed).
GET https://cdn.jsdelivr.net/npm/normalize.css@8/normalize.min.css
Failed to load ‘https://cdn.jsdelivr.net/npm/normalize.css@8/normalize.min.css’. A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while handling a ‘cors’ FetchEvent. Opaque Response objects are only valid when the RequestMode is ‘no-cors’. sw.js:1853:26
GET https://fonts.googleapis.com/css2?family=Open+Sans&display=block
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://fonts.googleapis.com/css2?family=Open+Sans&display=block. (Reason: CORS request did not succeed).
Failed to load ‘https://fonts.googleapis.com/css2?family=Open+Sans&display=block’. A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while handling a ‘cors’ FetchEvent. Opaque Response objects are only valid when the RequestMode is ‘no-cors’.
A Learn More
link sends here, where it talks about general network/http errors, but I don’t think that’s the case. Neither are adblockers, because chrome with external debugger starts blank, and my “Firefox Developer Edition” installation is blank.
Issue Analytics
- State:
- Created 3 years ago
- Comments:16 (7 by maintainers)
Top GitHub Comments
@wanderview was good enough to jump in with some debugging help, and figured out what’s going on.
The DevTools interface basically behaves like another client of the service worker, and in order to populate its user interface with details about the various resources being loaded, makes its own requests for each URL. When those requests are for cross-origin URLs, they’re made without CORS. Those non-CORS requests made by DevTools do trigger the service worker’s
fetch
handler, and the revalidation step in the Workbox strategy you’re using ends up using a non-CORS (opaque) response to populate the cache.That explains why opening DevTools triggers this behavior. The fact that you explicitly require a CORS response (due to the
crossorigin="anonymous"
attribute on your DOM elements) explains why you experience a complete failure to load the subresources.So… that’s a summary of what’s going on.
You can explicitly work around it in your specific use case by adding an instance of the
CacheableResponsePlugin
that requires a200
response status to your strategy:The documentation for
workbox-cacheable-response
includes an explanation of its usage and why some strategies default to caching opaque responses.Beyond resolving your specific issue, there are a couple of longer-term ways of following-up:
Do nothing. Given that this happens due to interaction with DevTools, it’s not likely to affect production users, but it can obviously cause frustration for developers if they frequently open DevTools and have subresources which require CORS responses and use a stale-while-revalidate or network-first strategy.
Change
workbox-routing
so that it explicitly detects requests that originate from DevTools (I’m assuming there’s a programmatic way of doing that via some header…) and ensure that Workbox doesn’t respond to thosefetch
events.Change the
StaleWhileRevalidate
andNetworkFirst
strategies to detect what the currently cached responses’stype
is, and if it’s not'opaque'
, refuse to overwrite it with an'opaque'
response.Change the
StaleWhileRevalidate
andNetworkFirst
strategies to detect what the currently cached responses’stype
is, and if it’s not'opaque'
, refuse to overwrite it with an'opaque'
response. Instead, perform an additionalfetch()
with an explicit'cors'
mode and revalidate the cache with that response instead.My personal preference is probably 2., but Ben points out that if Workbox refused to respond to DevTool’s requests, the DevTools interface may end up showing a different response that what the web page sees. You could imagine, for instance, a Workbox route that created a synthetic response by stitching together multiple partial sources. That synthetic response would not be visible to DevTools. So I’m not really sure what to do about that.
Option 3. might be the best compromise, but it does add in some extra overhead, and in the back of my head, I wonder whether there are any legitimate use cases that it would end up breaking.
For the meantime, it’s option 1. by default.
It seems like there’s some movement on the underlying issue at https://bugs.chromium.org/p/chromium/issues/detail?id=1092637, so I’m going to defer to the DevTools team to find a permanent resolution, as opposed to trying to address this in Workbox.