it-swarm.com.de

In der angeforderten Ressource ist kein Header "Access-Control-Allow-Origin" vorhanden, wenn versucht wird, Daten von einem zu erhalten REST API

Ich versuche, Daten von der REST - API von HP Alm abzurufen. Es funktioniert ziemlich gut mit einem kleinen Curl-Skript - ich bekomme meine Daten.

Jetzt mit JavaScript, Fetch und ES6 (mehr oder weniger) zu tun, scheint ein größeres Problem zu sein. Ich erhalte ständig diese Fehlermeldung:

Abruf-API kann nicht geladen werden. Antwort auf Preflight-Anfrage nicht Zugriffskontrollprüfung bestehen: Kein 'Access-Control-Allow-Origin'-Header ist auf der angeforderten Ressource vorhanden sein. Origin ' http://127.0.0.1:3000 ' lautet daher kein Zugriff erlaubt. Die Antwort hatte den HTTP-Statuscode 501 . Wenn eine undurchsichtige Antwort Ihren Anforderungen entspricht, setzen Sie den Modus der Anforderung auf 'no-cors' zum Abrufen der Ressource bei deaktiviertem CORS.

Ich verstehe, dass dies so ist, weil ich versuche, diese Daten aus meinem localhost abzurufen, und die Lösung sollte CORS verwenden. Jetzt dachte ich, ich hätte das tatsächlich getan, aber irgendwie ignoriert es entweder das, was ich in die Kopfzeile schreibe, oder ist das Problem etwas anderes? 

Gibt es also ein Implementierungsproblem? Mache ich es falsch? Ich kann die Serverprotokolle leider nicht überprüfen. Ich bin wirklich ein bisschen hier festgefahren.

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 benutze Chrome. Ich habe auch versucht, das Chrome CORS Plugin zu verwenden, aber dann bekomme ich eine weitere Fehlermeldung:

Der Wert des Headers 'Access-Control-Allow-Origin' in der Antwort darf nicht der Platzhalter '*' sein, wenn der Berechtigungsmodus der Anforderung .__ ist. 'umfassen'. Origin ' http://127.0.0.1:3000 ' ist daher nicht zulässig Zugriff. Der Anmeldeinformationsmodus für Anforderungen, die von .__ initiiert werden. XMLHttpRequest wird vom Attribut withCredentials gesteuert.

183
daniel.lozynski

Diese Antwort hat eine Menge zu bieten und gliedert sich in drei Teile:

  • Verwendung eines CORS-Proxys, um Probleme zu umgehen “Kein Zugriffskontroll-Erlaube-Herkunft-Header”
  • So vermeiden Sie den CORS-Preflight
  • Wie zu beheben “Access-Control-Allow-Origin-Header darf nicht der Platzhalter sein” Probleme

Wie man einen CORS-Proxy benutzt, um herumzukommen “Kein Access-Control-Allow-Origin-Header” Probleme

Wenn Sie den Server nicht steuern, an den Ihr Frontend-JavaScript-Code eine Anfrage sendet, und das Problem mit der Antwort von diesem Server nur das Fehlen des erforderlichen Access-Control-Allow-Origin - Headers ist, können Sie dennoch alles zum Laufen bringen. indem Sie die Anfrage über einen CORS-Proxy stellen. Um zu zeigen, wie das funktioniert, sehen Sie sich zunächst einen Code an, der keinen CORS-Proxy verwendet:

const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

Der Grund, warum der Block catch dort getroffen wird, ist, dass der Browser verhindert, dass dieser Code auf die Antwort zugreift, die von https://example.com Zurückkommt. Und der Grund, warum der Browser dies tut, ist, dass der Antwortkopf Access-Control-Allow-Origin Fehlt.

Hier ist genau das gleiche Beispiel, nur mit einem CORS-Proxy in:

const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

Hinweis: Wenn https://cors-anywhere.herokuapp.com beim Versuch nicht verfügbar oder nicht verfügbar ist, erfahren Sie weiter unten, wie Sie Ihren eigenen CORS Anywhere-Server bei Heroku bereitstellen in nur 2-3 Minuten.

Mit dem zweiten Code-Snippet oben kann erfolgreich auf die Antwort zugegriffen werden, da die Anforderungs-URL in https://cors-anywhere.herokuapp.com/https://example.com geändert wird, indem ihr lediglich ein Präfix vorangestellt wird mit der Proxy-URL: Bewirkt, dass die Anforderung über diesen Proxy erfolgt. Dieser führt dann Folgendes aus:

  1. Leitet die Anfrage an https://example.com Weiter.
  2. Erhält die Antwort von https://example.com.
  3. Fügt der Antwort den Header Access-Control-Allow-Origin Hinzu.
  4. Übergibt diese Antwort mit dem hinzugefügten Header an den anfordernden Frontend-Code.

Der Browser ermöglicht dann dem Frontend-Code, auf die Antwort zuzugreifen, da diese Antwort mit dem Antwortheader Access-Control-Allow-Origin Dem Browser entspricht.

Sie können Ihren eigenen Proxy einfach mit Code von https://github.com/Rob--W/cors-anywhere/ ausführen.
Mit 5 Befehlen können Sie Heroku auch ganz einfach in nur 2-3 Minuten Ihren eigenen Proxy bereitstellen:

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git Push heroku master

Nach dem Ausführen dieser Befehle wird Ihr eigener CORS Anywhere-Server beispielsweise unter https://cryptic-headland-94862.herokuapp.com/ ausgeführt. Anstatt also Ihrer Anforderungs-URL das Präfix https://cors-anywhere.herokuapp.com Voranzustellen, stellen Sie ihr stattdessen die URL für Ihre eigene Instanz voran. z. B. https://cryptic-headland-94862.herokuapp.com/https://example.com .

Wenn Sie also versuchen, https://cors-anywhere.herokuapp.com zu verwenden, stellen Sie fest, dass es nicht funktioniert (was es manchmal sein wird) Besorgen Sie sich dann ein Heroku-Konto (falls Sie dies noch nicht getan haben) und nehmen Sie sich zwei oder drei Minuten Zeit, um die oben genannten Schritte auszuführen, um Ihren eigenen CORS Anywhere-Server auf Heroku bereitzustellen.

Unabhängig davon, ob Sie einen eigenen ausführen oder https://cors-anywhere.herokuapp.com oder einen anderen offenen Proxy verwenden, funktioniert diese Lösung auch dann, wenn die Anforderung eine Anforderung ist, die den Browser zu einem CORS-Preflight veranlasst OPTIONS request - In diesem Fall sendet der Proxy auch die Header Access-Control-Allow-Headers und Access-Control-Allow-Methods zurück, die für einen erfolgreichen Preflight erforderlich sind.


So vermeiden Sie den CORS-Preflight

Der Code in der Frage löst einen CORS-Preflight aus, da ein Authorization -Header gesendet wird.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

Auch ohne das würde der Header Content-Type: application/json Den Preflight auslösen.

Was "Preflight" bedeutet: Bevor der Browser die POST im fraglichen Code versucht, sendet er zunächst eine OPTIONS -Anforderung an den Server, um festzustellen, ob der Server die Option aktiviert -in, um eine Cross-Origin-POST zu erhalten, die die Header Authorization und Content-Type: application/json enthält.

Es funktioniert ziemlich gut mit einem kleinen Curl-Skript - ich bekomme meine Daten.

Um mit curl richtig zu testen, müssen Sie die Preflight-Anforderung OPTIONS emulieren, die 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"

… Wobei https://the.sign_in.url Durch Ihre aktuelle sign_in URL ersetzt wird.

Die Antwort, die der Browser von dieser OPTIONS Anfrage erhalten soll, muss folgende Überschriften enthalten:

Access-Control-Allow-Origin:  http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization

Wenn die Antwort OPTIONS diese Header nicht enthält, stoppt der Browser sofort und versucht nicht einmal, die Anfrage POST zu senden. 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 Anforderung "OPTIONS" mit einem 501-Statuscode. Dies bedeutet anscheinend, dass versucht wird, anzuzeigen, dass keine Unterstützung für Anforderungen "OPTIONS" implementiert wird. In diesem Fall antworten andere Server in der Regel mit dem Statuscode 405 "Methode nicht zulässig".

Sie werden also niemals in der Lage sein, POST Anforderungen direkt von Ihrem Frontend-JavaScript-Code an diesen Server zu senden, wenn der Server auf diese OPTIONS Anforderung mit einer 405 oder 501 oder einer anderen antwortet als 200 oder 204 oder wenn nicht mit den erforderlichen Antwort-Headern reagiert.

Der Weg zu vermeiden, ein Preflight für den Fall in der Frage auszulösen, wäre:

  • wenn der Server keinen Anforderungsheader für Authorization benötigt, sondern sich stattdessen (beispielsweise) auf Authentifizierungsdaten stützt, die im Hauptteil der POST -Anforderung oder als Abfrageparameter eingebettet sind
  • wenn der Server für den Body der POST keinen Medientyp Content-Type: application/json benötigt, sondern stattdessen den Body der POST als application/x-www-form-urlencoded mit einem Parameter namens akzeptiert hat json (oder was auch immer), dessen Wert die JSON-Daten sind

Wie zu beheben "Access-Control-Allow-Origin-Header darf nicht der Platzhalter sein" Probleme

Ich erhalte eine weitere Fehlermeldung:

Der Wert des Headers 'Access-Control-Allow-Origin' in der Antwort darf nicht der Platzhalter '*' sein, wenn der Anmeldeinformationsmodus der Anforderung 'include' ist. Origin ' http://127.0.0.1:30 ' ist daher kein Zugriff gestattet. Der Anmeldeinformationsmodus von Anforderungen, die von XMLHttpRequest initiiert werden, wird vom withCredentials-Attribut gesteuert.

Bei einer Anfrage, die Anmeldeinformationen enthält, lassen Browser Ihren Frontend-JavaScript-Code nicht auf die Antwort zugreifen, wenn der Wert des Antwort-Headers Access-Control-Allow-Origin* Ist. Stattdessen muss der Wert in diesem Fall genau mit dem Ursprung Ihres Frontend-Codes übereinstimmen, http://127.0.0.1:3000.

Siehe Anforderungen mit Berechtigungsnachweis und Platzhalterzeichen im Artikel zur MDN-HTTP-Zugriffssteuerung (CORS).

Wenn Sie den Server steuern, an den Sie die Anforderung senden, können Sie diesen Fall in der Regel lösen, indem Sie den Server so konfigurieren, dass er den Wert des Anforderungsheaders Origin übernimmt und diesen zurückgibt der Wert des Antwortheaders Access-Control-Allow-Origin. Zum Beispiel mit nginx:

add_header Access-Control-Allow-Origin $http_Origin

Dies ist jedoch nur ein Beispiel. Andere (Web-) Serversysteme bieten ähnliche Möglichkeiten, um Origin-Werte wiederzugeben.


Ich benutze Chrome. Ich habe auch versucht, das Chrome CORS Plugin zu verwenden

Das Chrome CORS-Plugin fügt anscheinend einfach einen Access-Control-Allow-Origin: * - Header in die Antwort ein, die der Browser sieht. Wenn das Plugin schlauer wäre, würde es den Wert dieser Fälschung einstellen Access-Control-Allow-Origin - Antwortheader zum tatsächlichen Ursprung Ihres Frontend-JavaScript-Codes, http://127.0.0.1:3000.

Vermeiden Sie es also, dieses Plugin auch zum Testen zu verwenden. Es ist nur eine Ablenkung. Wenn Sie testen möchten, welche Antworten Sie vom Server erhalten, ohne dass der Browser sie filtert, sollten Sie wie oben beschrieben curl -H Verwenden.


Soweit der Frontend-JavaScript-Code für die fetch(…) -Anforderung in der Frage:

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

Entfernen Sie diese Linien. Die Access-Control-Allow-* - Header sind response Header. Sie möchten sie niemals in einer Anfrage senden. Der einzige Effekt ist, dass ein Browser einen Preflight durchführt.

507
sideshowbarker

Dieser Fehler tritt auf, wenn die Client-URL und die Server-URL einschließlich der Portnummer nicht übereinstimmen. In diesem Fall müssen Sie Ihren Dienst für CORS aktivieren, das die gemeinsame Nutzung der Origin-Ressourcen ermöglicht.

Wenn Sie einen Spring REST - Dienst hosten, finden Sie ihn im Blogbeitrag CORS-Unterstützung in Spring Framework.

Wenn Sie einen Dienst unter Verwendung eines Node.js-Servers hosten, dann

  1. Stoppen Sie den Node.js-Server.
  2. npm install cors
  3. Fügen Sie Ihrer server.js folgende Zeilen hinzu

    var cors = require('cors')
    
    app.use(cors()) // Use this after the variable declaration
    
39
Rakesh

Das Problem trat auf, weil Sie den folgenden Code als request -Header in Ihrem Frontend hinzugefügt haben:

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

Diese Header gehören zu Antwort, nicht zu request. Also remove, einschließlich der Zeile: 

headers.append('GET', 'POST', 'OPTIONS');

Ihre Anfrage lautete 'Content-Type: application/json' und wurde daher als CORS-Preflight bezeichnet. Dies hat dazu geführt, dass der Browser die Anforderung mit der Methode OPTIONS gesendet hat. Siehe CORS Preflight für detaillierte Informationen. 
Daher müssen Sie in Ihrem back-end diese vorgefertigte Anforderung behandeln, 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 sein:

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));
}
1
Lex Soft

Die Verwendung von 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               
0
hoogw

Entferne das:

credentials: 'include',
0

In meinem Fall hat der Webserver die Methode "OPTIONS" verhindert

Überprüfen Sie Ihren Webserver auf die Optionsmethode

Ich benutze "webtier"

/www/webtier/domains/[domainname)/config/fmwconfig/components/OHS/VCWeb1/httpd.conf

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]
</IfModule>

ändern

<IfModule mod_rewrite.c>
  RewriteEngine off
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]
</IfModule>
0
Juneho Nam

Nur meine zwei Cent ... in Bezug auf Wie verwende ich einen CORS-Proxy, um Probleme mit "No Access-Control-Allow-Origin-Header" zu umgehen?

Für diejenigen unter Ihnen, die mit PHP im Backend arbeiten, ist die Bereitstellung eines "CORS-Proxys" so einfach wie:

  1. erstelle eine datei namens 'no-cors.php' mit folgendem inhalt:

    $ URL = $ _GET ['url']; echo json_encode (file_get_contents ($ URL)); sterben();

  2. mach auf deinem Frontend so etwas wie:

    fetch (' https://example.com/no-cors.php ' + '? url =' + url) .then (response => {/Handle Response/})

0
Yair Levy

Ich habe mit Spring REST gearbeitet und es gelöst, indem ich die AllowedMethods in den WebMvcConfigurer eingefügt habe.

@Value( "${app.allow.origins}" )
    private String allowOrigins;    
@Bean
public WebMvcConfigurer corsConfigurer() {
            System.out.println("allow Origin: "+allowOrigins);
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                    //.allowedOrigins("http://localhost")
                    .allowedOrigins(allowOrigins)
                    .allowedMethods("PUT", "DELETE","GET", "POST");
                }
            };
        }
0
Jorge Dominguez