Warum wird bei Postman nicht der Fehler "Kein Zugriffssteuerungs-Zulassen-Ursprung" für die angeforderte Ressource vorhanden "angezeigt, wenn mein JavaScript-Code dies tut?

2502

Mod-Hinweis : Bei dieser Frage geht es darum, warum Postman nicht wie eine XMLHttpRequest CORS-Einschränkungen unterliegt. In dieser Frage geht es nicht darum, wie ein Fehler "Nein 'Zugriffskontrolle-Zulassen-Ursprung' ..." behoben werden kann.

Bitte hör auf zu posten :


Ich versuche, die Autorisierung mithilfe von JavaScript durchzuführen, indem ich eine Verbindung zum integrierten RESTful- API - Flask herstelle . Wenn ich jedoch die Anfrage stelle, wird folgende Fehlermeldung angezeigt:

XMLHttpRequest kann http: // myApiUrl / login nicht laden . In der angeforderten Ressource ist kein Header 'Access-Control-Allow-Origin' vorhanden. Origin 'null' ist daher kein Zugriff gestattet.

Ich weiß, dass die API oder die Remote-Ressource den Header festlegen muss, aber warum hat es funktioniert, als ich die Anfrage über die Chrome-Erweiterung Postman gestellt habe ?

Dies ist der Anforderungscode:

$.ajax({
    type: "POST",
    dataType: 'text',
    url: api,
    username: 'user',
    password: 'pass',
    crossDomain : true,
    xhrFields: {
        withCredentials: true
    }
})
    .done(function( data ) {
        console.log("done");
    })
    .fail( function(xhr, textStatus, errorThrown) {
        alert(xhr.responseText);
        alert(textStatus);
    });
Herr Jedi
quelle
32
Führen Sie die Anfrage von localhost aus oder führen Sie HTML direkt aus?
MD. Sahib Bin Mahboob
@ MD.SahibBinMahboob Wenn ich Ihre Frage verstehe, fordere ich sie von localhost an - ich habe eine Seite auf meinem Computer und führe sie einfach aus. Wenn ich eine Site beim Hosting bereitstelle, wird das gleiche Ergebnis erzielt.
Herr Jedi
8
Für alle, die mehr lesen möchten, hat MDN einen guten Artikel über Ajax- und Cross-Origin-Anfragen: developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Sam Eaton
1
Ein wichtiger Hinweis für diese Art von Fehler in Knoten js. Sie MÜSSEN Ihre Zugriffskopfzeilen beim Start Ihrer Datei server.js festlegen, bevor Sie mit dem Einrichten Ihrer Routen beginnen. Andernfalls läuft alles einwandfrei, aber Sie erhalten diesen Fehler, wenn Sie Anfragen von Ihrer App stellen.
Alex J

Antworten:

1346

Wenn ich es richtig verstanden habe, führen Sie eine XMLHttpRequest für eine andere Domain durch, auf der sich Ihre Seite befindet. Der Browser blockiert es also, da er aus Sicherheitsgründen normalerweise eine Anfrage desselben Ursprungs zulässt. Sie müssen etwas anderes tun, wenn Sie eine domänenübergreifende Anfrage stellen möchten. Ein Tutorial, wie dies erreicht werden kann, ist die Verwendung von CORS .

Wenn Sie Postboten verwenden, sind diese nicht durch diese Richtlinie eingeschränkt. Zitiert aus Cross-Origin XMLHttpRequest :

Normale Webseiten können das XMLHttpRequest-Objekt zum Senden und Empfangen von Daten von Remoteservern verwenden, sie sind jedoch durch dieselbe Ursprungsrichtlinie beschränkt. Erweiterungen sind nicht so begrenzt. Eine Nebenstelle kann mit Remoteservern außerhalb ihres Ursprungs kommunizieren, sofern sie zuerst originalübergreifende Berechtigungen anfordert.

MD. Sahib Bin Mahboob
quelle
7
Du hast recht. Ich beantrage eine andere Domain als meine Seite. Die API befindet sich auf dem Server und ich führe eine Anfrage von localhost aus. Bevor ich die Antwort akzeptiere, können Sie mir erklären, was "direkte Ausführung der Anfrage" bedeutet? POSTMAN Domain nicht verwenden?
Herr Jedi
181
Der Browser blockiert die Anfrage nicht. Der einzige Browser, der augenübergreifende Ajax-Anforderungen vollständig blockiert, ist IE7 oder älter. Alle Browser außer IE7 und älter implementieren die CORS-Spezifikation (IE8 und IE9 teilweise). Sie müssen sich lediglich für CORS-Anforderungen auf Ihrem API-Server anmelden, indem Sie die richtigen Header basierend auf der Anforderung zurückgeben. Informationen zu CORS-Konzepten finden Sie unter mzl.la/VOFrSz . Postbote sendet Anfragen auch über XHR. Wenn Sie bei der Verwendung von Postman nicht das gleiche Problem feststellen, bedeutet dies, dass Sie unwissentlich nicht dieselbe Anfrage per Postman senden.
Ray Nicholus
10
@ MD.SahibBinMahboob Postman sendet KEINE Anfrage "von Ihrem Java / Python" -Code. Es sendet die Anfrage direkt vom Browser. XHR in Chrome-Erweiterungen funktionieren etwas anders, insbesondere wenn es sich um originensübergreifende Anforderungen handelt .
Ray Nicholus
250

WARNUNG: Durch Access-Control-Allow-Origin: *die Verwendung kann Ihre API / Website für CSRF-Angriffe ( Cross-Site Request Forgery ) anfällig werden . Stellen Sie sicher, dass Sie die Risiken verstanden haben, bevor Sie diesen Code verwenden.

Es ist sehr einfach zu lösen, wenn Sie PHP verwenden . Fügen Sie einfach das folgende Skript am Anfang Ihrer PHP-Seite hinzu, das die Anfrage bearbeitet:

<?php header('Access-Control-Allow-Origin: *'); ?>

Wenn Sie Node-Red verwenden , müssen Sie CORS in der node-red/settings.jsDatei zulassen, indem Sie die folgenden Zeilen auskommentieren:

// The following property can be used to configure cross-origin resource sharing
// in the HTTP nodes.
// See https://github.com/troygoode/node-cors#configuration-options for
// details on its contents. The following is a basic permissive set of options:
httpNodeCors: {
 origin: "*",
 methods: "GET,PUT,POST,DELETE"
},

Wenn Sie Flask wie in der Frage verwenden; Sie müssen zuerst installierenflask-cors

$ pip install -U flask-cors

Nehmen Sie dann die Kolbenkors in Ihre Anwendung auf.

from flask_cors import CORS

Eine einfache Anwendung sieht folgendermaßen aus:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

Weitere Informationen finden Sie in der Kolbendokumentation .

Schattiger Sherif
quelle
93
und es ist nicht sicher
llazzaro
153
Sie sollten CORS nicht ausschalten, weil Sie nicht wissen, wofür es ist. Das ist eine schreckliche Antwort.
Meagar
124
Auch wenn es möglicherweise nicht sicher ist, ging es nicht um Sicherheit, sondern darum, wie die Aufgabe zu erfüllen ist. Dies ist eine der Optionen, aus denen ein Entwickler auswählen muss, wenn er domänenübergreifende AJAX-Anforderungen bearbeitet. Es hat mir geholfen, das Problem zu beheben, und für meine Anwendung ist es mir egal, woher die Daten stammen. Ich bereinige alle Eingaben mit PHP in der Zieldomäne. Wenn also jemand Müll darauf posten möchte, lass es ihn versuchen. Der Hauptpunkt hierbei ist, dass domänenübergreifendes AJAX von der Zieldomäne aus zugelassen werden kann. +1 für die Antwort.
ZurabWeb
23
Obwohl ich der allgemeinen Botschaft von Piero zustimme, geht es nicht speziell um Sicherheit, sondern um Sicherheit. Ich denke, dies hätte zumindest etwas wie "Das ist im Allgemeinen schlecht! Tun Sie dies nicht, es sei denn, Sie wissen, was Sie tun! Hier ist mehr Dokumentation dazu: ..." und vielleicht kurz erklären, warum. Ich würde es hassen, wenn jemand hierher kommt und einfach denkt: "Oh, ich kann diesen Header einfach hinzufügen / anpassen und ich bin gut!" und nicht die vollständigen Auswirkungen kennen. Ich meine, es liegt irgendwie an ihnen zu recherchieren und so weiter, aber immer noch.
Thomas F.
4
Ich mag diese Antwort ... Ich habe das gleiche Problem und es löst es ... Er erklärte, dass es einige Sicherheitsprobleme gibt, aber das ist ein anderes Problem und lässt jeden individuell über dieses Problem nachdenken und es lösen ...
Ari Waisberg
64

Weil
$ .ajax ({Typ: "POST" - ruft OPTIONS
$ .post auf ( - ruft POST auf

Beide sind unterschiedlich. Der Postbote ruft "POST" richtig auf, aber wenn wir es nennen, wird es "OPTIONEN" sein.

Für C # -Webdienste - Web-API

Bitte fügen Sie den folgenden Code in Ihre web.config- Datei unter dem Tag <system.webServer> ein. Das wird funktionieren:

<httpProtocol>
    <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
    </customHeaders>
</httpProtocol>

Bitte stellen Sie sicher, dass Sie beim Ajax-Anruf keinen Fehler machen

jQuery

$.ajax({
    url: 'http://mysite.microsoft.sample.xyz.com/api/mycall',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    type: "POST", /* or type:"GET" or type:"PUT" */
    dataType: "json",
    data: {
    },
    success: function (result) {
        console.log(result);
    },
    error: function () {
        console.log("error");
    }
});

Hinweis: Wenn Sie zum Herunterladen von Inhalten suchen aus einer Drittanbieter - Website dann wird dies Ihnen nicht helfen . Sie können den folgenden Code ausprobieren, jedoch nicht JavaScript.

System.Net.WebClient wc = new System.Net.WebClient();
string str = wc.DownloadString("http://mysite.microsoft.sample.xyz.com/api/mycall");
George Livingston
quelle
Diese Konfiguration hat denselben Fehler in Wordpress bei Azure Services behoben. Vielen Dank.
Andre Mesquita
9
Ich würde vorschlagen, einen bestimmten Ursprungswert zu verwenden, um Anfragen von externen Domänen zu vermeiden. Also zum Beispiel statt zu *benutzenhttps://www.myotherdomain.com
Pechar
Der Link hubfly.com/blog/solutions/how-to-fix-angular-4-api-call-issues ist defekt (404).
Peter Mortensen
8

Das Anwenden einer CORS-Einschränkung ist eine Sicherheitsfunktion, die von einem Server definiert und von einem Browser implementiert wird .

Der Browser überprüft die CORS-Richtlinie des Servers und respektiert sie.

Das Postman-Tool kümmert sich jedoch nicht um die CORS-Richtlinie des Servers.

Aus diesem Grund wird der CORS-Fehler im Browser angezeigt, nicht jedoch in Postman.

Gopinath
quelle
1
Ja, ich kann nicht genug betonen, warum dieses kleine Detail etwas Aufmerksamkeit verdient. Wenn es um Sicherheit geht, muss unbedingt erwähnt werden, dass CORS nur so stark ist wie der Client , der es implementiert. Stellen Sie sich vor, Sie nehmen einen einfachen HttpClient (serverseitigen Code) und erstellen einen Proxy, der dann Ihre Anforderungen erfüllt ... Die Sicherheit kann vollständig umgangen werden, sodass der CORS-Standard wirklich eine schlechte Lösung bleibt
Christopher Bonitz
7

In der folgenden Untersuchung als API verwende ich http://example.com anstelle von http: // myApiUrl / login aus Ihrer Frage, da diese erste funktioniert.

Ich gehe davon aus, dass sich Ihre Seite unter http: //my-site.local: 8088 befindet .

Der Grund, warum Sie unterschiedliche Ergebnisse sehen, ist, dass Postbote:

  • Header setzen Host=example.com(Ihre API)
  • NICHT Header setzen Origin

Dies ähnelt der Art und Weise, wie Browser Anforderungen senden, wenn die Site und die API dieselbe Domäne haben (Browser legen auch das Header-Element fest Referer=http://my-site.local:8088, ich sehe es jedoch nicht in Postman). Wenn der OriginHeader nicht festgelegt ist, lassen Server solche Anforderungen normalerweise standardmäßig zu.

Geben Sie hier die Bildbeschreibung ein

Dies ist die Standardmethode, mit der Postman Anfragen sendet. Ein Browser sendet Anforderungen jedoch anders, wenn Ihre Site und API unterschiedliche Domänen haben. Dann tritt CORS auf und der Browser automatisch:

  • Setzt den Header Host=example.com(Ihren als API)
  • Setzt den Header Origin=http://my-site.local:8088(Ihre Site)

(Der Header Refererhat den gleichen Wert wie Origin). Und jetzt sehen Sie auf der Registerkarte " Konsole und Netzwerke" von Chrome Folgendes :

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Wenn Host != Origindies CORS ist und der Server eine solche Anforderung erkennt, blockiert er diese normalerweise standardmäßig .

Origin=nullwird festgelegt, wenn Sie HTML-Inhalte aus einem lokalen Verzeichnis öffnen und eine Anforderung senden. Die gleiche Situation ist, wenn Sie eine Anfrage innerhalb eines senden <iframe>, wie im folgenden Snippet (aber hier ist der HostHeader überhaupt nicht gesetzt) ​​- im Allgemeinen können Sie dies überall dort übersetzen, wo die HTML-Spezifikation undurchsichtigen Ursprung sagt Origin=null. Weitere Informationen hierzu finden Sie hier .

fetch('http://example.com/api', {method: 'POST'});
Look on chrome-console > network tab

Wenn Sie keine einfache CORS-Anfrage verwenden, sendet der Browser normalerweise automatisch auch eine OPTIONS-Anfrage, bevor Sie die Hauptanforderung senden. Weitere Informationen finden Sie hier . Das folgende Snippet zeigt es:

fetch('http://example.com/api', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json'}
});
Look in chrome-console -> network tab to 'api' request.
This is the OPTIONS request (the server does not allow sending a POST request)

Sie können die Konfiguration Ihres Servers ändern, um CORS-Anforderungen zuzulassen.

Hier ist eine Beispielkonfiguration, die CORS unter nginx aktiviert (Datei nginx.conf). Seien Sie sehr vorsichtig bei der Einstellung always/"$http_origin"für nginx und "*"Apache. Dadurch wird CORS von jeder Domäne entsperrt.

Hier ist eine Beispielkonfiguration, die CORS in Apache aktiviert (.htaccess-Datei)

Kamil Kiełczewski
quelle
2

In verschiedenen Anwendungsfällen ist derselbe Fehler aufgetreten.

Anwendungsfall: In Chrom, wenn versucht wird, den Spring REST- Endpunkt im Winkel aufzurufen .

Geben Sie hier die Bildbeschreibung ein

Lösung: Fügen Sie die Annotation @CrossOrigin ("*") über der jeweiligen Controller-Klasse hinzu.

Geben Sie hier die Bildbeschreibung ein

Kms
quelle
Ich benutze localhost anstelle von * für die Sicherheit
neo7bf
-1

Wenn Sie .NET als mittlere Ebene verwenden, überprüfen Sie das Routenattribut deutlich, z.

Ich hatte ein Problem, als es so war,

[Route("something/{somethingLong: long}")] //Space.

Es wurde dadurch behoben,

[Route("something/{somethingLong:long}")] //No space
Sai Vaibhav Medavarapu
quelle
-1

Fügen Sie nur für .NET Core Web API-Projekte folgende Änderungen hinzu:

  1. Fügen Sie nach der services.AddMvc()Zeile in der ConfigureServices()Methode der Datei Startup.cs den folgenden Code ein :
services.AddCors(allowsites=>{allowsites.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
            });
  1. Fügen Sie den folgenden Code nach der app.UseMvc()Zeile in die Configure()Methode der Datei Startup.cs ein:
app.UseCors(options => options.AllowAnyOrigin());
  1. Öffnen Sie den Controller, auf den Sie außerhalb der Domäne zugreifen möchten, und fügen Sie auf Controller-Ebene das folgende Attribut hinzu:
[EnableCors("AllowOrigin")]
Shakti Srivastav
quelle