Ich habe eine Webseite ( https://smartystreets.com/contact ), die jQuery verwendet, um einige SVG-Dateien von S3 über das CloudFront-CDN zu laden.
In Chrome öffne ich ein Inkognito-Fenster sowie die Konsole. Dann lade ich die Seite. Beim Laden der Seite werden in der Regel 6 bis 8 Meldungen in der Konsole angezeigt, die ungefähr so aussehen:
XMLHttpRequest cannot load
https://d79i1fxsrar4t.cloudfront.net/assets/img/feature-icons/documentation.08e71af6.svg.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'https://smartystreets.com' is therefore not allowed access.
Wenn ich die Seite mehrmals standardmäßig neu lade, werden weiterhin dieselben Fehler angezeigt. Wenn ich das tue, werden die Command+Shift+R
meisten und manchmal alle Bilder ohne XMLHttpRequest
Fehler geladen .
Manchmal aktualisiere ich sogar nach dem Laden der Bilder, und eines oder mehrere der Bilder werden nicht geladen und geben diesen XMLHttpRequest
Fehler erneut zurück.
Ich habe die Einstellungen in S3 und Cloudfront überprüft, geändert und erneut überprüft. In S3 sieht meine CORS Konfiguration so aus:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedOrigin>http://*</AllowedOrigin>
<AllowedOrigin>https://*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>
(Hinweis: hatte anfangs nur das <AllowedOrigin>*</AllowedOrigin>
gleiche Problem.)
In Cloudfront ist das Verteilungsverhalten der HTTP - Methoden ermöglichen gesetzt: GET, HEAD, OPTIONS
. Die zwischengespeicherten Methoden sind dieselben. Forward Headers ist auf "Whitelist" gesetzt und diese Whitelist enthält "Access-Control-Request-Headers, Access-Control-Request-Method, Origin".
Die Tatsache, dass es nach einem Browser-Reload ohne Cache funktioniert, scheint darauf hinzudeuten, dass auf der S3 / CloudFront-Seite alles in Ordnung ist. Andernfalls wird der Inhalt geliefert. Aber warum wird der Inhalt dann nicht auf der ersten Seite angezeigt?
Ich arbeite in Google Chrome auf MacOS. Firefox hat kein Problem damit, die Dateien jedes Mal abzurufen. Opera bekommt NIE die Dateien. Safari nimmt die Bilder nach mehreren Aktualisierungen auf.
Mit curl
bekomme ich keine Probleme:
curl -I -H 'Origin: smartystreets.com' https://d79i1fxsrar4t.cloudfront.net/assets/img/phone-icon-outline.dc7e4079.svg
HTTP/1.1 200 OK
Content-Type: image/svg+xml
Content-Length: 508
Connection: keep-alive
Date: Tue, 20 Jun 2017 17:35:57 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Last-Modified: Thu, 15 Jun 2017 16:02:19 GMT
ETag: "dc7e4079f937e83291f2174853adb564"
Cache-Control: max-age=31536000
Expires: Wed, 01 Jan 2020 23:59:59 GMT
Accept-Ranges: bytes
Server: AmazonS3
Vary: Origin,Access-Control-Request-Headers,Access-Control-Request-Method
Age: 4373
X-Cache: Hit from cloudfront
Via: 1.1 09fc52f58485a5da8e63d1ea27596895.cloudfront.net (CloudFront)
X-Amz-Cf-Id: wxn_m9meR6yPoyyvj1R7x83pBDPJy1nT7kdMv1aMwXVtHCunT9OC9g==
Einige haben vorgeschlagen, die CloudFront-Distribution zu löschen und neu zu erstellen. Scheint eine ziemlich harte und unbequeme Lösung zu sein.
Was verursacht dieses Problem?
Aktualisieren:
Hinzufügen von Antwortheadern aus einem Bild, das nicht geladen werden konnte.
age:1709
cache-control:max-age=31536000
content-encoding:gzip
content-type:image/svg+xml
date:Tue, 20 Jun 2017 17:27:17 GMT
expires:2020-01-01T23:59:59.999Z
last-modified:Tue, 11 Apr 2017 18:17:41 GMT
server:AmazonS3
status:200
vary:Accept-Encoding
via:1.1 022c901b294fedd7074704d46fce9819.cloudfront.net (CloudFront)
x-amz-cf-id:i0PfeopzJdwhPAKoHpbCTUj1JOMXv4TaBgo7wrQ3TW9Kq_4Bx0k_pQ==
x-cache:Hit from cloudfront
quelle
Antworten:
Sie stellen zwei Anforderungen für dasselbe Objekt, eine aus HTML und eine aus XHR. Die zweite schlägt fehl, weil Chrome die zwischengespeicherte Antwort der ersten Anfrage verwendet, die keinen
Access-Control-Allow-Origin
Antwortheader hat.Warum?
Chromium-Fehler 409090 Eine ursprungsübergreifende Anforderung aus dem Cache, die fehlschlägt, nachdem die reguläre Anforderung zwischengespeichert wurde, beschreibt dieses Problem und wird nicht behoben. Sie glauben, dass ihr Verhalten korrekt ist. Chrome betrachtet die zwischengespeicherte Antwort als verwendbar, anscheinend, weil die Antwort keinen
Vary: Origin
Header enthielt .S3 wird jedoch nicht zurückgegeben,
Vary: Origin
wenn ein Objekt ohneOrigin:
Anforderungsheader angefordert wird , auch wenn CORS im Bucket konfiguriert ist.Vary: Origin
wird nur gesendet, wenn einOrigin
Header in der Anfrage vorhanden ist.Und CloudFront fügt
Vary: Origin
selbst dann keineOrigin
Whitelists für die Weiterleitung hinzu, was per Definition bedeuten sollte, dass eine Änderung des Headers die Antwort ändern kann - aus diesem Grund leiten Sie weiter und stellen den Cache für Anforderungsheader bereit.CloudFront erhält einen Pass, da seine Antwort korrekt wäre, wenn S3 korrekter wäre, da CloudFront dies zurückgibt, wenn es von S3 bereitgestellt wird.
S3, etwas unschärfer. Es ist nicht falsch , zurückzukehren,
Vary: Some-Header
wennSome-Header
die Anfrage keine enthält .Es
Vary: Some-Absent-Header
ist eindeutig gültig, also wäre S3 richtig, wenn esVary: Origin
zu seiner Antwort hinzugefügt würde , wenn CORS konfiguriert ist, da dies tatsächlich die Antwort variieren könnte.Und dies würde Chrome anscheinend dazu bringen, das Richtige zu tun. Oder, wenn es in diesem Fall nicht das Richtige tut, würde es a verletzen
MUST NOT
. Aus demselben Abschnitt:S3
SHOULD
kehrt also wirklich zurück,Vary: Origin
wenn CORS im Bucket konfiguriert ist, wennOrigin
es in der Anforderung nicht vorhanden ist, aber nicht.Trotzdem ist S3 nicht unbedingt falsch, wenn der Header nicht zurückgegeben wird, da es sich nur um a
SHOULD
, nicht um a handeltMUST
. Aus demselben Abschnitt von RFC-7231:Andererseits könnte argumentiert werden, dass Chrome implizit wissen sollte, dass das Variieren des
Origin
Headers ein Cache-Schlüssel sein sollte, da dies die Antwort auf die gleiche WeiseAuthorization
ändern könnte, wie dies die Antwort ändern könnte.In ähnlicher Weise wird die Wiederverwendung über die Ursprünge hinweg wohl durch die Natur der Sache eingeschränkt,
Origin
aber dieses Argument ist kein starkes.tl; dr: Sie können ein Objekt anscheinend nicht erfolgreich aus HTML abrufen und es dann als CORS-Anforderung mit Chrome und S3 (mit oder ohne CloudFront) erneut erfolgreich abrufen, da Besonderheiten in den Implementierungen vorliegen.
Problemumgehung:
Dieses Verhalten kann mit CloudFront und Lambda @ Edge umgangen werden, indem der folgende Code als Origin Response-Trigger verwendet wird.
Dies fügt
Vary: Access-Control-Request-Headers, Access-Control-Request-Method, Origin
jeder Antwort von S3 hinzu, die keinenVary
Header hat. Andernfalls wird derVary
Header in der Antwort nicht geändert.Namensnennung: Ich bin auch der Autor des ursprünglichen Posts in den AWS-Support-Foren, in denen dieser Code ursprünglich geteilt wurde.
Die oben beschriebene Lambda @ Edge-Lösung führt zu einem vollständig korrekten Verhalten. Je nach Ihren spezifischen Anforderungen können jedoch zwei Alternativen hilfreich sein:
Alternative / Problemumgehung Nr. 1: Schmieden Sie die CORS-Header in CloudFront.
CloudFront unterstützt benutzerdefinierte Header, die jeder Anfrage hinzugefügt werden. Wenn Sie
Origin:
für jede Anforderung festlegen , auch wenn es sich nicht um eine ursprungsübergreifende Anforderung handelt, wird das korrekte Verhalten in S3 aktiviert. Die Konfigurationsoption heißt "Custom Origin Headers", wobei das Wort "Origin" etwas völlig anderes bedeutet als in CORS. Wenn Sie einen benutzerdefinierten Header wie diesen in CloudFront konfigurieren, wird der in der Anforderung gesendete Wert mit dem angegebenen Wert überschrieben oder bei Abwesenheit hinzugefügt. Wenn Sie genau einen Ursprung haben, der über XHR auf Ihre Inhalte zugreifthttps://example.com
, können Sie diesen hinzufügen. Die Verwendung*
ist zweifelhaft, funktioniert jedoch möglicherweise in anderen Szenarien. Betrachten Sie die Auswirkungen sorgfältig.Alternative / Problemumgehung Nr. 2: Verwenden Sie einen "Dummy" -Abfragezeichenfolgenparameter, der sich für HTML und XHR unterscheidet oder in der einen oder anderen nicht vorhanden ist. Diese Parameter werden normalerweise benannt
x-*
, sollten es aber nicht seinx-amz-*
.Nehmen wir an, Sie erfinden den Namen
x-request
. Also<img src="https://dzczcexample.cloudfront.net/image.png?x-request=html">
. Fügen Sie den Abfrageparameter nicht hinzu, wenn Sie von JS aus auf das Objekt zugreifen. CloudFront macht bereits das Richtige, indem verschiedene Versionen der Objekte mithilfe desOrigin
Headers oder ohne diesen als Teil des Cache-Schlüssels zwischengespeichert werden, da Sie diesen Header in Ihrem Cache-Verhalten weitergeleitet haben. Das Problem ist, dass Ihr Browser dies nicht weiß. Dies überzeugt den Browser, dass dies tatsächlich ein separates Objekt ist, das in einem CORS-Kontext erneut angefordert werden muss.Wenn Sie diese alternativen Vorschläge verwenden, verwenden Sie den einen oder den anderen - nicht beide.
quelle
?x-some-key=some-value
Abfragezeichenfolgenparameters wird der Browser davon überzeugt, dass die Anforderung anders ist.Ich weiß nicht, warum Sie von verschiedenen Browsern so unterschiedliche Ergebnisse erhalten, aber:
In dieser Zeile wird ein CloudFront- oder Support-Techniker (sofern Sie darauf aufmerksam werden können) eine Ihrer fehlgeschlagenen Anfragen beantworten. Wenn die Anforderung an einen CloudFront-Server gesendet wird, sollte dieser Header in der Antwort enthalten sein. Wenn dieser Header nicht vorhanden ist, schlägt die Anforderung wahrscheinlich irgendwo fehl, bevor sie zu CloudFront gelangt.
quelle