简体   繁体   中英

Angular Service Worker ngsw-config.json S3/Cloudflare Image Caching CORS Error

In an Angular 9 app, when I add this image caching snippet to ngsw-config.json, I get a CORS error and images don't display. If I remove this snippet the app works correctly (with no errors).

Access to fetch at 'https://assets.myurl.net/images/banner.jpg' from origin 'https://localhost:8100' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

ngsw-config.json (snippet):

"assetGroups": [{
    "name": "cdn",
    "installMode": "lazy",
    "updateMode": "lazy",
    "resources": {
        "urls": [
            "https://assets.myurl.net/**"
        ]
    }
}]

Images are stored in an AWS S3 bucket with CORS configuration:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
</CORSRule>
</CORSConfiguration>
  • Cloudflare is being used as a CDN (and DNS).
  • The app is on the latest 9.x releases: @angular 9.2.1, @angular/service-worker 9.1.12.
  • Adding crossorigin="anonymous" to img and picture tags didn't seem to help.

Steps to consistently reproduce the error in Chrome/PC:

  1. Clear browser cache
  2. Open browser private/incognito
  3. Go to website -- images show okay
  4. Click refresh -- images no longer show - CORS errors in browser console

UPDATE

Based on this post ( S3 not returning Access-Control-Allow-Origin headers? ) the issue appears to be that the service worker does not send an Origin in the request header (so S3 doesn't send access-control headers).

Service Worker Request (copied from Chrome console):

Request URL: https://assets.myurl.net/images/banner.jpg
Referrer Policy: strict-origin-when-cross-origin
Provisional headers are shown
Referer: https://localhost:8100/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36

First of all, make sure an Origin header with every request. If no Origin header is sent, S3 won't send access-control headers, as S3 deems them irrelevant (and typically, they are). A browser (for which the CORS mechanism is meant) will automatically send an Origin header when doing cross-origin HTTP requests through XMLHTTPRequest.

Based on this post ( S3 - Access-Control-Allow-Origin Header ) the S3 cors script has been updated to include:

<AllowedMethod>HEAD</AllowedMethod>
<AllowedHeader>*</AllowedHeader>

Adding crossorigin="anonymous" to img tags doesn't change the service worker request header. So this doesn't fix the problem.

Cloudflare cache has been purged.

This obscure post ( https://community.cloudflare.com/t/access-control-allow-origin-headers-stripped/158102/2 ) includes:

If you add or change CORS configuration at your origin web server, purging the Cloudflare cache by URL does NOT update the CORS headers.

I cache busted the banner.jpg image by adding a random querystring (ie banner.jpg?q=abc). The banner image always displays correctly (while the other images still show cors errors). The service worker cache in Chrome console Application Tab > Cache Storage shows that the image as cached. Cloudflare caching configuration "Caching Level" = Standard "delivers a different resource each time the query string changes".

缓存

However, if I upload a new image to S3 banner01.jpg (ie not already cached by Cloudflare) I do get a cors error showing this image. I tried this three additional times by uploading different image names and did not get a cors error. Interestingly, an hour later even the new images are showing cors errors.

A curl command (that does not specify Origin in header) runs successfully on my local PC. The response does not contain CORS headers. eg

curl -v "https://assets.myurl.net/images/banner.jpg"

Adding origin to the curl command does return CORS headers. eg

curl -v --header "Origin: https://www.example.com" "https://assets.myurl.net/images/banner.jpg"

access-control-allow-origin: https://www.example.com
access-control-allow-methods: GET, HEAD
access-control-allow-credentials: true

UPDATE 2

I can't explain why, but Chrome now returns cors headers in the Angular Service Worker fetch response. The request does NOT include an Origin header.

accept-ranges: bytes
access-control-allow-methods: GET, HEAD
access-control-allow-origin: *

However, Safari does not. All browsers appear to be working okay but Safari still shows cors errors.

Go to your S3 bucket. Click on Permissions, then CORS configuration. If you have a CORS configuration, change the allowed origin from this:

<AllowedOrigin>*</AllowedOrigin>

TO

<AllowedOrigin>http://*</AllowedOrigin>
<AllowedOrigin>https://*</AllowedOrigin>

If you don't have a CORS configuration, add a config like this:

<CORSConfiguration>
<CORSRule>
    <AllowedOrigin>http://*</AllowedOrigin>
    <AllowedOrigin>https://*</AllowedOrigin>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
</CORSRule>
</CORSConfiguration>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM