So wenden Sie den CORS-Preflight-Cache auf eine gesamte Domain an

78

Ich erstelle eine REST-Anwendung, die CORS verwendet. Jeder REST-Aufruf ist anders und ich stelle fest, dass das Abrufen des Preflight-OPTIONS-Aufrufs einen erheblichen Aufwand bedeutet. Gibt es eine Möglichkeit, ein Preflight-OPTIONS-Ergebnis zwischenzuspeichern und anzuwenden, sodass nachfolgende Aufrufe derselben Domäne die zwischengespeicherte Antwort verwenden?

MindWire
quelle
1
Anhang zur Frage: Wenn das Zwischenspeichern von Preflights für einen kleineren Bereich nicht möglich ist, wie kann die Anzahl der Preflight-Anforderungen in einer RESTful-Anwendung am besten begrenzt werden?
Rob W
1
Mit einem Reverse-Proxy, Check-out von Nginx, können Sie die CORS-Strafe vor dem Flug vermeiden. Einfach map / api -> api.site.com
Douglas Ferguson
Der Wikipedia-Artikel über CORS enthält ein schönes Flussdiagramm, mit dessen Hilfe ich verstehen konnte, unter welchen Bedingungen ein Preflight-Anruf getätigt werden würde (und wie ich sie vermeiden kann).
Trenton

Antworten:

104

Preflight kann nur auf die Anforderung angewendet werden, nicht auf die gesamte Domain. Ich habe dieselbe Frage auf die Mailingliste gesetzt, und es gab Sicherheitsbedenken. Hier ist der gesamte Thread: http://lists.w3.org/Archives/Public/public-webapps/2012AprJun/0228.html

Es gibt einige Dinge zu beachten, wenn Sie die Anzahl der Preflight-Anfragen begrenzen möchten. Beachten Sie zunächst, dass WebKit / Blink-basierte Browser einen maximalen Preflight-Cache von 10 Minuten festlegen:

https://github.com/WebKit/webkit/blob/master/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp https://chromium.googlesource.com/chromium/blink/+/master/Source/core/loader/CrossOriginPreflightR .cpp

(Ich bin nicht sicher, ob dies für andere Browser gilt). Während Sie also immer den Header Access-Control-Max-Age festlegen sollten, beträgt der Maximalwert 10 Minuten.

Nächster Hinweis: Es ist unmöglich, einen Preflight bei PUT / DELETE-Anforderungen zu vermeiden. Für Aktualisierungen / Löschungen Ihrer API ist daher mindestens alle 10 Minuten ein Preflight erforderlich.

Vermeiden Sie bei GET / POST nach Möglichkeit benutzerdefinierte Header, da diese weiterhin Preflights auslösen. Wenn Ihre API JSON zurückgibt, beachten Sie, dass ein Inhaltstyp von 'application / json' auch einen Preflight auslöst.

Wenn Sie bereit sind, zu verbiegen, wie "RESTful" Ihre API ist, können Sie noch einige weitere Dinge ausprobieren. Eine Möglichkeit besteht darin, einen Inhaltstyp zu verwenden, für den kein Preflight erforderlich ist, z. B. "Text / Plain". Benutzerdefinierte Header lösen immer Preflights aus. Wenn Sie also benutzerdefinierte Header haben, können Sie diese in Abfrageparameter verschieben. Am äußersten Ende könnten Sie ein Protokoll wie JSON-RPC verwenden, bei dem alle Anforderungen an einen einzelnen Endpunkt gestellt werden.

Ehrlich gesagt ist der Preflight-Cache aufgrund des Preflight-Cache-Limits des Browsers von 10 Minuten und der REST-Ressourcen-URLs ziemlich nutzlos. Es gibt sehr wenig, was Sie tun können, um Preflights im Verlauf einer lang laufenden App einzuschränken. Ich bin zuversichtlich, dass die Autoren der CORS-Spezifikation versuchen werden, dies in Zukunft zu beheben.

Monsur
quelle
3
@uglymunky Ich werde diesen Abschnitt klarstellen. Der Schlüssel des Preflight-Caches basiert auf einem Ursprungs- / URL-Paar, wobei die URL die vollständige Anforderungs-URL ist. Was ich damit gemeint habe ist, dass wenn Sie einen benutzerdefinierten Header haben, dieser immer einen Preflight auslöst, selbst bei einer GET-Anfrage. Wenn Sie diesen benutzerdefinierten Header jedoch in einen Abfrageparameter verschieben, gibt es keinen Preflight für GET / POST-Anforderungen.
Monsur
2
@monsur Hallo, etwas spät zur Party, habe mich aber gefragt, ob Sie raten könnten. Ich übergebe derzeit einen Autorisierungsheader (z. B. "Basic [base64-codierte Zeichenfolge]") mit allen Anforderungen an meine API. Die Preflight-Anfragen beeinträchtigen die Leistung der App erheblich. Wenn ich zu einem tokenbasierten Authentifizierungssystem wechseln würde (mit dem Token als QS-Parameter in der URL) und benutzerdefinierte Header vollständig entfernen würde, wäre dies eine Möglichkeit, die gefürchteten OPTIONS-Anforderungen für GET und POST zu vermeiden (I ' Ist es in Ordnung, wenn es welche für PUT und DELETE gibt?
Adam
5
@adaam das sollte den Trick machen. Ich habe gerade einige Tests in Firefox und Chrome durchgeführt, um das Verhalten besser zu verstehen, und kann dies teilen: Wenn Ihr benutzerdefinierter Header vorhanden ist, löst der Browser eine OPTIONS-Anforderung aus, es sei denn, der Access-Control-Max-Ageist vorhanden und genau dieselbe URL wurde von gesehen Der Browser zuvor und innerhalb des von Access-Control-Max-Ageund angegebenen Bereichs verkürzt den Wert nicht (Webkit, Firefox). Wenn Sie die benutzerdefinierten Header entfernen und in die URL verschieben, sendet der Browser die OPTIONS-Anforderung nicht. Sieg!
Mikegradek
2
Ich finde es toll, dass sie einfach nicht mehr auf Ihre E-Mails antworten. All diese redundanten Aufrufe für einen Single-Edge-Fall.
Rebs
3
In Ihrer Antwort ist die Einschränkung des Inhaltstyps nur beim Senden von Daten relevant , nicht beim Empfangen. Daher gibt es kein Problem mit Servern, die beliebige Header vom Inhaltstyp zurückgeben.
Letmaik
6

Versuchen Sie es mit xDomain

Es war ziemlich einfach für mich einzurichten, wenn ich Angular oder jQuery verwendete. Fügen Sie auf Ihrem App-Server eine proxy.html hinzu, wie in der Hilfe unter dem folgenden Link angegeben. Fügen Sie einige Tags hinzu, die auf die js-Dateien auf Ihrem "Client" und Ihrer Bratsche verweisen, keine Vorflüge mehr. Dies wird in einen Iframe eingeschlossen, um die Notwendigkeit einer Cors-Überprüfung zu vermeiden.

https://github.com/jpillora/xdomain

Zäh
quelle
1

Eine Möglichkeit besteht darin, dass Sie alle Ihre API-Aufrufe auf dieselbe Domäne wie Ihr Front-End verweisen können. Richten Sie nginx auf dem Front-End-Server so ein, dass nur API-Aufrufe an den API-Server weitergeleitet werden. Dadurch werden alle Anrufe vor dem Flug entfernt.

Kishor Borat
quelle