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

Sep 10 2020

In un'app Angular 9, quando aggiungo questo frammento di memorizzazione nella cache dell'immagine a ngsw-config.json, ottengo un errore CORS e le immagini non vengono visualizzate. Se rimuovo questo frammento l'app funziona correttamente (senza errori).

L'accesso per il recupero su "https://assets.myurl.net/images/banner.jpg" dall'origine "https: // localhost: 8100" è stato bloccato dal criterio CORS: nessuna intestazione "Access-Control-Allow-Origin" è presente sulla risorsa richiesta. Se una risposta opaca soddisfa le tue esigenze, imposta la modalità della richiesta su "no-cors" per recuperare la risorsa con CORS disabilitato.

ngsw-config.json (frammento):

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

Le immagini vengono archiviate in un bucket AWS S3 con configurazione CORS:

<?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 viene utilizzato come CDN (e DNS).
  • L'app è sulle ultime versioni 9.x: @angular 9.2.1, @ angular / service-worker 9.1.12.
  • L'aggiunta di crossorigin = "anonymous" ai tag img e picture non sembra essere d'aiuto.

Passaggi per riprodurre costantemente l'errore in Chrome / PC:

  1. Cancella la cache del browser
  2. Apri browser privato / in incognito
  3. Vai al sito web - le immagini mostrano bene
  4. Fare clic su Aggiorna - le immagini non vengono più visualizzate - Errori CORS nella console del browser

AGGIORNARE

Sulla base di questo post ( S3 non restituisce le intestazioni Access-Control-Allow-Origin? ), Il problema sembra essere che il service worker non invia un'origine nell'intestazione della richiesta (quindi S3 non invia intestazioni di controllo dell'accesso).

Richiesta Service Worker (copiata dalla console Chrome):

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

Prima di tutto, assicurati un'intestazione Origin con ogni richiesta. Se non viene inviata alcuna intestazione Origin, S3 non invierà intestazioni di controllo degli accessi, poiché S3 le ritiene irrilevanti (e in genere lo sono). Un browser (per il quale si intende il meccanismo CORS) invierà automaticamente un'intestazione Origin quando si eseguono richieste HTTP cross-origin tramite XMLHTTPRequest.

Sulla base di questo post ( S3 - Access-Control-Allow-Origin Header ) lo script S3 cors è stato aggiornato per includere:

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

L'aggiunta di crossorigin = "anonymous" ai tag img non modifica l'intestazione della richiesta di service worker. Quindi questo non risolve il problema.

La cache di Cloudflare è stata eliminata.

Questo oscuro post (https://community.cloudflare.com/t/access-control-allow-origin-headers-stripped/158102/2) include:

Se aggiungi o modifichi la configurazione CORS sul server Web di origine, l'eliminazione della cache di Cloudflare tramite URL NON aggiorna le intestazioni CORS.

Ho eliminato nella cache l'immagine banner.jpg aggiungendo una stringa di query casuale (ad esempio banner.jpg? Q = abc). L'immagine del banner viene sempre visualizzata correttamente (mentre le altre immagini mostrano ancora errori di cors). La cache di service worker nella scheda Applicazione della console Chrome> Archiviazione cache mostra l'immagine come memorizzata nella cache. Configurazione della cache di Cloudflare "Livello di cache" = Standard "fornisce una risorsa diversa ogni volta che la stringa di query cambia".

Tuttavia, se carico una nuova immagine su S3 wi-fi (cioè non è già stata memorizzata nella cache da Cloudflare) ottengo un errore cors che mostra questa immagine. Ho provato a farlo altre tre volte caricando diversi nomi di immagine e non ho ricevuto un errore cors. È interessante notare che un'ora dopo anche le nuove immagini mostrano errori di cors.

Un comando curl (che non specifica l'origine nell'intestazione) viene eseguito correttamente sul mio PC locale. La risposta non contiene intestazioni CORS. per esempio

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

L'aggiunta di origine al comando curl restituisce le intestazioni CORS. per esempio

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

AGGIORNAMENTO 2

Non riesco a spiegare perché, ma Chrome ora restituisce le intestazioni cors nella risposta di recupero di Angular Service Worker. La richiesta NON include un'intestazione Origin.

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

Tuttavia, Safari non lo fa. Tutti i browser sembrano funzionare bene, ma Safari mostra ancora errori di cors.

Risposte

LeonGrin Sep 19 2020 at 20:50

Vai al tuo bucket S3. Fare clic su Autorizzazioni, quindi su Configurazione CORS. Se hai una configurazione CORS, modifica l'origine consentita da questa:

<AllowedOrigin>*</AllowedOrigin>

PER

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

Se non hai una configurazione CORS, aggiungi una configurazione come questa:

<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>