Guten Abend,
kann mir hier jemand auf einfache Weise erklären, wie CORS im
Zusammenhang eines lokal ausgeführten Javascriptes und einer PHP API auf
einem Webserver funktioniert?
Ich habe auf beiden Seiten ein "*" für den Origin vergeben, bekomme aber
keine Daten geliefert.
Wenn das Skript auf dem Webserver liegt, funktioniert es.
Danke und Gruß
Kolja
Der Browser checkt beim erhalt der Antwort, ob der Origin passt. Per
default ist der erlaubte Origin der von der Url, wo der Request hin
soll. Aber wenn der Server den "Access-Control-Allow-Origin" mit der
Antwort mit senden, können noch weitere origins erlaubt werden. Der
Origin, der mit dem erlaubtem gegengecheckt wird, ist der der Seite, die
das script ausführt. Der origin ist der Teil der url aus
schema://domain:port, ohne den Pfad dahinter. In manchen speziellen
Situationen (z.B. wenn Authentifizierungsdaten per SSO mitgesendet
werden sollen) macht der Browser aber vor dem echten request noch einem
OPTION request, um zuerst zu prüfen, ob der request gemacht werden darf.
Bei dem option request ist dann aber das gleiche spiel. Es gibt noch ein
paar andere cors header, z.B. einer für die erlaubten Methoden. In
manchen Situationen & für manche cors header funktioniert auch der wert
* nicht, da muss man dann explizit sein. Das ist auch, warum gewisse
APIs Access-Control-Allow-Origin auf den Wert des Origin headers vom
Request setzen.
Kolja L. schrieb:> Wenn das Skript auf dem Webserver liegt
Wenn es nicht am Webserver ist, ist es dann eine lokale Datei? Wie will
die einen "Access-Control-Allow-Origin"-Header mitschicken, wenn sie
geöffnet wird?
Danke DPA für die ausführliche Antwort, jetzt ist mir das Prinzip schon
etwas deutlicher geworden.
Aber zum "Laufen" habe ich es noch nicht bekommen.
Ich liste mal auf ;-)
Das ist die Fehlermeldung vom Browser,
wenn ich meine Seite auf einem lokalen Server ausführe und die Daten vom
Webserver anfordere:
1
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://dev.irgendwo.de/savemydata/api/login. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.
2
3
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://dev.irgendwo.de/savemydata/api/login. (Reason: CORS request did not succeed). Status code: (null).
Ich würde mal mit "curl -v" oder einem Tool wie postman oder so mal
nachsehen, ob die Header auch tatsächlich gesetzt werden.
In php kann man die header nur setzen, solange sie noch nicht gesendet
sind. u.A. darf also noch nichts ausgegeben worden sein. Dass kann recht
schnell mal passieren, z.B. wenn man einen abstand, newline, oder
unicode BOM vor dem <?php stehen hat, oder sonst irgendwo im Code
irgendwas ausgegeben wurde. Wenn die Warnungen ausgeschaltet sind,
bekommt man davon auch gar nichts mit.
Weitere Fehlerquelle, hängt aber evtl. auch mit dem verfrühtem Output
vor den header() - Aufrufen zusammen:
der Browser kann die Cors-Header per "HEAD"-Request abfragen, da hast du
dann keine POST-Daten, musst aber trotzdem die Header ausliefern.
Und das PHP-Script wird dann evtl. beim ersten Output abgebrochen, da
der HEAD-Request keinen Body erwartet.
Bin gerade nicht zuhause, aber würde bei einer PHP Ausgabe vor dem
header das ganze nicht auch nicht funktionieren, wenn das JavaScript auf
dem Server liegt?
Das ist es ja, was mich so irritiert. Liegt beides auf dem Webserver
funktioniert es, liegt das JS auf dem lokalen Server, geht es nicht.
Die Browserfehlermeldung sagt ja recht eindeutig das dev.irgendwo.de
scheinbar real keinen Access-Control-Allow-Origin HTTP-Header sendet.
Da würde ich im Netzwerk-Tab in den Dev-Tools des Browsers (F12-Taste)
als erstes mal nachschauen wie die Header im Response und der Response
selbst denn tatsächlich aussehen...
bluppdidupp schrieb:> Da würde ich im Netzwerk-Tab in den Dev-Tools des Browsers (F12-Taste)> als erstes mal nachschauen wie die Header im Response und der Response> selbst denn tatsächlich aussehen...
Ich habe da mit cross origin geschichten schlechte erfahrungen mit den
browser dev tools gemacht. Die zeigen da nicht immer alles 1:1, bei den
cors geschichten.
So, nach etwas warten hat sich das Problem leider nicht von selbst
behoben,
aber ich habe mir die Abfrage aus dem Projekt extrahiert, um evtl.
Kreuzreaktionen zu verhindern.
Die api.php wird über XAMPP (Apache/PHP) ausgegeben und die JS Anfrage
über den "Live-Server" des VSCode Editors gestellt.
Es bleibt aber bei demselben Fehler:
> Access to fetch at 'http://localhost./php/api.php?list'; from origin
'http://127.0.0.1:5500'; 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.
Die Anfrage ist denkbar simpel:
Es ist die einzige Ausgabe der PHP-Datei (auch keine Warnungen, Fehler
etc.) und wenn die Abfrage auch über XAMPP aufgerufen wird, funktioniert
es.
In der gewünschten Konstellation (Abfrage und Antwort auf verschiedenen
(lokalen) Servern, gibt es nach der Anfrage (Kopfzeile aus den
DevTools):
1
Accept: */*
2
Accept-Encoding: gzip, deflate, br
3
Accept-Language: de,en-US;q=0.7,en;q=0.3
4
Connection: keep-alive
5
Host: localhost.
6
Origin: http://127.0.0.1:5500
7
Referer: http://127.0.0.1:5500/
8
Sec-Fetch-Dest: empty
9
Sec-Fetch-Mode: cors
10
Sec-Fetch-Site: cross-site
11
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:98.0) Gecko/20100101 Firefox/98.0
folgende Antwort:
1
scheme: https
2
host: localhost.
3
filename: /php/api.php
4
Übertragen: 0B (0 B Größe)
5
Referrer Policy: strict-origin-when-cross-origin
Hat dazu noch jemand eine Idee, oder gebe ich das Problem jetzt einfach
auf?
Gruß Kolja
Kolja L. schrieb:> kann mir hier jemand auf einfache Weise erklären, wie CORS im> Zusammenhang eines lokal ausgeführten Javascriptes und einer PHP API auf> einem Webserver funktioniert?
Wiso?
Bei der Antwort ist am Anfang vermutlich noch ein "GET /php/api.php
HTTP/1.1" oder so, dass man nicht sieht.
Die Antwort sieht merkwürdig aus. Diese Header (scheme:, filename:
Übertragen:) habe ich in einer HTTP/1.1 Response noch nie gesehen. (und
wieso scheme:https, wenn im fetch http steht?!?). Den
"Access-Control-Allow-Origin" Header sieht man da auch nicht.
Kannst du eventuell mit Wireshark oder so nochmal nachsehen, ob da nicht
was anderes gesendet wird?
Oder macht der Server da vielleicht sogar irgend welchen experimentellen
HTTP/2 / SPDY oder HTTP/3 / QUIC Nonsens, der da zu Problemen führt?
Du musst auf dem Server zwei HTTP Methoden implementieren:
> OPTIONS http://localhost./php/api.php?list
Muss mit einem leeren Body und folgenden Header beantwortet werden:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 86400
Diese Requests hast du in deinen Logs womöglich nicht gesehen, weil der
Browser die Berechtigungen cached, so dass er den OPTIONS Request beim
Wiederhol-versuch normalerweise nicht erneut sendet.
Danach ruft der Browser auf:
> GET http://localhost./php/api.php?list
Das muss mit folgendem Header beantwortet werden:
Access-Control-Allow-Origin: *
und was du sonst noch so als Response zurück geben wolltest.
Anstelle der Sternchen kannst du natürlich restriktiver sein
(Komma-separierte Listen), aber damit würde ich erstmal anfangen.
Der Status 404 erscheint mir wichtig. Offenbar findet es die Datei unter
"http://localhost./php/api.php?list" nicht. Vermutlich ist dass das
Hauptproblem.
Vermutlich hat der Server Probleme mit dem "localhost." Spezifischer,
dem . am Schluss. "localhost." ist zwar eine gültige fqdn, es ist das
selbe wie localhost, nur dass die search Domains beim DNS Lookup nicht
beachtet werden. Nur senden Browser dann "Host: localhost." auch statt
"Host: localhost", und die meisten Webserver oft nicht so clever zu
merken, dass "Host: localhost." und localhost den selben vhost betreffen
sollten. (Zumindest nicht ohne spezielle Zusatzkonfigurationen)
Also nimm den . da mal weg, damit da "http
://localhost/php/api.php?list" draus wird. Oder alternativ, mach aus dem
"http ://localhost" statdessen "http ://localhost/", dann wird daraus
"http ://localhost/./php/api.php?list", was dann wieder passen sollte.
Alternativ kann man die URL auch mit der URL Klasse zusammensetzen:
🐧 DPA 🐧 schrieb:> Der Status 404 erscheint mir wichtig. Offenbar findet es die Datei unter> "http://localhost./php/api.php?list"; nicht. Vermutlich ist dass das> Hauptproblem.
JA :-)
Ohne Punkt und mit dem o.g. Header für die OPTIONs funktioniert es!
Danke, vor allem Stefan und DPA für Eure Hilfe,
jetzt muss das ganze nur noch im Hauptprojekt auch funktionieren.
Gruß Kolja
Kolja L. schrieb:> Und damit funktioniert es auch im "großen" Projekt :-)
Meinst du damit die Produktivumgebung?
Ich dachte da gehts ohne, weil es dort kein "Cross-Origin" sondern
sowieso "Same-Origin" ist.
Dann solltest du dort auch ohne Not keine CORS-Header setzen, vor allem
keine so weit gefassten mit "*".