Ich versuche, einige Daten von der REST-API von HP Alm abzurufen. Es funktioniert ziemlich gut mit einem kleinen Curl-Skript – ich bekomme meine Daten.
Jetzt scheint dies mit JavaScript, Fetch und ES6 (mehr oder weniger) ein größeres Problem zu sein. Ich bekomme immer diese Fehlermeldung:
Abruf-API kann nicht geladen werden. Die Antwort auf die Preflight-Anfrage besteht die Zugriffssteuerungsprüfung nicht: Für die angeforderte Ressource ist kein Header „Access-Control-Allow-Origin“ vorhanden. Herkunft ‘http://127.0.0.1:3000‘ wird daher kein Zugriff gewährt. Die Antwort hatte den HTTP-Statuscode 501. Wenn eine undurchsichtige Antwort Ihren Anforderungen entspricht, setzen Sie den Modus der Anfrage auf „no-cors“, um die Ressource mit deaktiviertem CORS abzurufen.
Ich verstehe, dass dies daran liegt, dass ich versuche, diese Daten von meinem Localhost abzurufen und die Lösung CORS verwenden sollte. Jetzt dachte ich, ich hätte das tatsächlich getan, aber irgendwie ignoriert es entweder, was ich in die Kopfzeile schreibe, oder das Problem ist etwas anderes?
Gibt es also ein Implementierungsproblem? Mache ich es falsch? Leider kann ich die Serverlogs nicht einsehen. Ich stecke hier wirklich etwas fest.
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
headers.append('GET', 'POST', 'OPTIONS');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
fetch(sign_in, {
//mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
Ich verwende Chrome. Ich habe auch versucht, dieses Chrome CORS-Plugin zu verwenden, aber dann erhalte ich eine andere Fehlermeldung:
Der Wert des Headers „Access-Control-Allow-Origin“ in der Antwort darf nicht der Platzhalter „*“ sein, wenn der Berechtigungsnachweismodus der Anforderung „include“ ist. Herkunft ‘http://127.0.0.1:3000‘ wird daher kein Zugriff gewährt. Der Berechtigungsnachweismodus von Anforderungen, die von XMLHttpRequest initiiert werden, wird durch das Attribut withCredentials gesteuert.
Diese Antwort deckt viele Bereiche ab und ist daher in drei Teile unterteilt:
- So verwenden Sie einen CORS-Proxy, um sich fortzubewegen „Kein Access-Control-Allow-Origin-Header“ Probleme
- So vermeiden Sie den CORS-Preflight
- Wie repariert man „Access-Control-Allow-Origin-Header darf kein Platzhalter sein“ Probleme
So vermeiden Sie die Verwendung eines CORS-Proxys „Kein Access-Control-Allow-Origin-Header“ Probleme
Wenn Sie den Server nicht kontrollieren, an den Ihr Frontend-Code eine Anfrage sendet, und das Problem mit der Antwort von diesem Server ist nur das Fehlen des Notwendigen Access-Control-Allow-Origin
-Header können Sie die Dinge trotzdem zum Laufen bringen, indem Sie die Anfrage über einen CORS-Proxy stellen.
Sie können Ihren eigenen Proxy ganz einfach mit Code von ausführen https://github.com/Rob–W/cors-anywhere/.
Sie können auch ganz einfach Ihren eigenen Proxy in nur 2-3 Minuten mit 5 Befehlen in Heroku bereitstellen:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
Nachdem Sie diese Befehle ausgeführt haben, wird Ihr eigener CORS Anywhere-Server ausgeführt, z. https://cryptic-headland-94862.herokuapp.com/
.
Stellen Sie nun Ihrer Anfrage-URL die URL für Ihren Proxy voran:
https://cryptic-headland-94862.herokuapp.com/https://example.com
Wenn Sie die Proxy-URL als Präfix hinzufügen, wird die Anfrage über Ihren Proxy gesendet, was:
- Leitet die Anfrage weiter an
https://example.com
.
- Erhält die Antwort von
https://example.com
.
- Fügt die hinzu
Access-Control-Allow-Origin
Kopfzeile zur Antwort.
- Übergibt diese Antwort mit diesem hinzugefügten Header zurück an den anfordernden Frontend-Code.
Der Browser erlaubt dann dem Frontend-Code, auf die Antwort zuzugreifen, da diese Antwort mit der Access-Control-Allow-Origin
Antwortheader ist das, was der Browser sieht.
Dies funktioniert auch dann, wenn die Anfrage Browser dazu veranlasst, einen CORS-Preflight durchzuführen OPTIONS
Anfrage, denn in diesem Fall sendet der Proxy auch die Access-Control-Allow-Headers
und Access-Control-Allow-Methods
Kopfzeilen, die für einen erfolgreichen Preflight benötigt werden.
So vermeiden Sie den CORS-Preflight
Der Code in der Frage löst einen CORS-Preflight aus, da er eine sendet Authorization
Header.
https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Auch ohne das Content-Type: application/json
Header löst auch einen Preflight aus.
Was „Preflight“ bedeutet: bevor der Browser das versucht POST
im Code in der Frage sendet es zuerst eine OPTIONS
Anfrage an den Server, um festzustellen, ob der Server dem Empfang eines Cross-Origin zustimmt POST
das hat Authorization
und Content-Type: application/json
Kopfzeilen.
Es funktioniert ziemlich gut mit einem kleinen Curl-Skript – ich bekomme meine Daten.
Um richtig zu testen curl
müssen Sie den Preflight emulieren OPTIONS
Der Browser sendet:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
…mit https://the.sign_in.url
ersetzt durch was auch immer Ihre aktuelle sign_in
URL ist.
Die Antwort, die der Browser davon benötigt OPTIONS
Anfrage muss Header wie diese haben:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Wenn die OPTIONS
Antwort diese Header nicht enthält, wird der Browser genau dort anhalten und niemals versuchen, die zu senden POST
Anfrage. Außerdem muss der HTTP-Statuscode für die Antwort 2xx sein – normalerweise 200 oder 204. Wenn es sich um einen anderen Statuscode handelt, stoppt der Browser genau dort.
Der Server in der Frage antwortet auf die OPTIONS
Anfrage mit einem 501-Statuscode, was anscheinend bedeutet, dass es versucht, anzuzeigen, dass es keine Unterstützung für implementiert OPTIONS
Anfragen. Andere Server antworten in diesem Fall normalerweise mit dem Statuscode 405 „Methode nicht erlaubt“.
Sie werden es also nie schaffen POST
Anfragen direkt von Ihrem Frontend-JavaScript-Code an diesen Server, wenn der Server darauf antwortet OPTIONS
Anfrage mit 405 oder 501 oder irgendetwas anderem als 200 oder 204 oder antwortet nicht mit diesen erforderlichen Antwortheadern.
Der Weg, um das Auslösen eines Preflights für den Fall in der Frage zu vermeiden, wäre:
- wenn der Server keine benötigt
Authorization
Request-Header, sondern stützte sich stattdessen zB auf Authentifizierungsdaten, die in den Body der eingebettet sind POST
Anfrage oder als Abfrageparameter
- wenn der Server das nicht benötigt
POST
Körper haben a Content-Type: application/json
Medientyp akzeptiert aber stattdessen die POST
Körper als application/x-www-form-urlencoded
mit einem Parameter namens json
(oder was auch immer), dessen Wert die JSON-Daten sind
Wie repariert man „Access-Control-Allow-Origin-Header darf kein Platzhalter sein“ Probleme
Ich bekomme eine weitere Fehlermeldung:
Der Wert des Headers „Access-Control-Allow-Origin“ in der Antwort
darf nicht der Platzhalter „*“ sein, wenn der Berechtigungsnachweismodus der Anfrage lautet
‘enthalten’. Herkunft ‘http://127.0.0.1:3000
“ ist daher nicht zulässig
betreten. Der Berechtigungsnachweismodus von Anfragen, die von initiiert wurden
XMLHttpRequest wird durch das withCredentials-Attribut gesteuert.
Bei Anforderungen mit Anmeldeinformationen lassen Browser Ihren Front-End-JavaScript-Code nicht auf die Antwort zugreifen, wenn der Wert der Access-Control-Allow-Origin
Kopfzeile ist *
. Stattdessen muss der Wert in diesem Fall genau mit dem Ursprung Ihres Frontend-Codes übereinstimmen, http://127.0.0.1:3000
.
Sehen Berechtigte Anfragen und Wildcards im Artikel MDN HTTP Access Control (CORS).
Wenn Sie den Server steuern, an den Sie die Anfrage senden, besteht eine gängige Methode, mit diesem Fall umzugehen, darin, den Server so zu konfigurieren, dass er den Wert von übernimmt Origin
Request-Header, und geben Sie dies in den Wert von zurück Access-Control-Allow-Origin
Antwortheader; zB mit nginx:
add_header Access-Control-Allow-Origin $http_origin
Aber das ist nur ein Beispiel; andere (Web-)Serversysteme haben ähnliche Möglichkeiten, Ursprungswerte zu echoen.
Ich verwende Chrome. Ich habe auch versucht, dieses Chrome CORS-Plugin zu verwenden
Dieses Chrome-CORS-Plug-in fügt anscheinend nur einfältig eine ein Access-Control-Allow-Origin: *
Header in die Antwort, die der Browser sieht. Wenn das Plugin intelligenter wäre, würde es den Wert dieser Fälschung festlegen Access-Control-Allow-Origin
Response-Header zum tatsächlichen Ursprung Ihres Frontend-JavaScript-Codes, http://127.0.0.1:3000
.
Vermeiden Sie es also, dieses Plugin zu verwenden, auch nicht zum Testen. Es ist nur eine Ablenkung. Um zu testen, welche Antworten Sie vom Server erhalten, ohne dass ein Browser sie filtert, verwenden Sie besser curl -H
wie oben.
Soweit der Frontend-JavaScript-Code für die fetch(…)
Anfrage in der Frage:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Entfernen Sie diese Zeilen. Die Access-Control-Allow-*
Überschriften sind Antwort Kopfzeilen. Sie möchten ihnen niemals Anfragen senden. Der einzige Effekt davon ist, dass ein Browser dazu veranlasst wird, einen Preflight durchzuführen.
Dieser Fehler tritt auf, wenn die Client-URL und die Server-URL nicht übereinstimmen, einschließlich der Portnummer. In diesem Fall müssen Sie Ihren Dienst für CORS aktivieren, was eine ursprungsübergreifende Ressourcenfreigabe ist.
Wenn Sie einen Spring-REST-Dienst hosten, finden Sie ihn im Blogbeitrag CORS-Unterstützung im Spring Framework.
Wenn Sie einen Dienst mit einem Node.js-Server hosten, dann
- Stoppen Sie den Node.js-Server.
npm install cors --save
- Fügen Sie Ihrer server.js die folgenden Zeilen hinzu
const cors=require("cors");
const corsOptions ={
origin:'*',
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200,
}
app.use(cors(corsOptions)) // Use this after the variable declaration
Das Problem ist aufgetreten, weil Sie den folgenden Code als hinzugefügt haben Anfrage Header in Ihrem Frontend:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Diese Header gehören zu den Antwort, nicht anfordern. Damit Löschen sie, einschließlich der Zeile:
headers.append('GET', 'POST', 'OPTIONS');
Ihre Anfrage hatte 'Content-Type: application/json'
, wodurch das sogenannte CORS-Preflight ausgelöst wurde. Dies führte dazu, dass der Browser die Anfrage mit der OPTIONS-Methode gesendet hat. Sehen CORS-Preflight für detaillierte Informationen.
Daher in Ihrer Backendmüssen Sie diese Preflight-Anforderung verarbeiten, indem Sie die Antwortheader zurückgeben, die Folgendes enthalten:
Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept
Die tatsächliche Syntax hängt natürlich von der Programmiersprache ab, die Sie für Ihr Backend verwenden.
In Ihrem Frontend sollte es so aussehen:
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
headers.append('Origin','http://localhost:3000');
fetch(sign_in, {
mode: 'cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed: ' + error.message));
}
In meinem Fall verwende ich die folgende Lösung.
Front-End oder Angular
post(
this.serverUrl, dataObjToPost,
{
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
)
Backend (ich benutze PHP)
header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);
Verwenden dataType: 'jsonp'
hat bei mir funktioniert.
async function get_ajax_data(){
var _reprojected_lat_lng = await $.ajax({
type: 'GET',
dataType: 'jsonp',
data: {},
url: _reprojection_url,
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR)
},
success: function (data) {
console.log(data);
// note: data is already json type, you
// just specify dataType: jsonp
return data;
}
});
} // function