AJAX in Chrome sendet OPTIONEN anstelle von GET / POST / PUT / DELETE?


107

Ich arbeite an einer internen Webanwendung bei der Arbeit. In IE10 funktionieren die Anforderungen einwandfrei, aber in Chrome werden alle AJAX-Anforderungen (von denen es viele gibt) mit OPTIONEN anstelle der von mir angegebenen Methode gesendet. Technisch gesehen sind meine Anfragen "domänenübergreifend". Die Site wird auf localhost: 6120 bereitgestellt, und der Dienst, an den ich AJAX-Anfragen stelle, befindet sich auf 57124. Dieser geschlossene Abfragefehler definiert das Problem, ist jedoch keine echte Lösung.

Was kann ich tun, um die richtige http-Methode in Ajax-Anfragen zu verwenden?

Bearbeiten:

Dies ist in der Dokumentenladung jeder Seite:

jQuery.support.cors = true;

Und jeder AJAX ist ähnlich aufgebaut:

var url = 'http://localhost:57124/My/Rest/Call';
$.ajax({
    url: url,
    dataType: "json",
    data: json,
    async: true,
    cache: false,
    timeout: 30000,
    headers: { "x-li-format": "json", "X-UserName": userName },
    success: function (data) {
        // my success stuff
    },
    error: function (request, status, error) {
        // my error stuff
    },
    type: "POST"
});

2
Der letzte Kommentar in diesem Fehlerbericht erklärt es ziemlich gut ...
Kevin B

1
Es hat mich umgehauen, weil alles, was ich tue, so vanillig ist (und mein Code ähnelt dem im jquery-Bug). Abgesehen davon ist es keine Entschuldigung dafür, es nicht aufzunehmen. BRB greift nach einem Beispielcode.
Corey Ogburn

3
Beachten Sie, dass der IE keine Portnummern berücksichtigt, wenn festgestellt wird, ob eine Anforderung einen Ursprungsübergang hat.
Ray Nicholus

@ KevinB: Unser REST-Service nutzt verschiedene Anforderungen, um verschiedene Dinge basierend auf der http-Methode zu erledigen. Das Umschalten auf GET ist keine gültige Lösung. Laut der Antwort von Dark Falcon wird es auch nicht helfen, da ich X-UserName und andere benutzerdefinierte Header in den Anfragen habe.
Corey Ogburn

Dies ändert nichts an der Tatsache, dass Sie, wenn Sie eine Ursprungsanfrage stellen möchten, alle Regeln befolgen müssen, die für Ursprungsanfragen gelten, damit sie ordnungsgemäß funktionieren. Ursprungsübergreifende Anforderungen umfassen normalerweise eine OPTIONS-Anforderung. Behandeln Sie es richtig und das Problem wird verschwinden. Die einzige andere Möglichkeit, dies zu lösen (ohne die API zu ändern), besteht darin, ein Skript auf demselben Server wie die Primärseite zu haben, das mit der API unter Verwendung von serverseitigem Code interagiert.
Kevin B

Antworten:


136

Chrome prüft vorab die Anfrage, nach CORS- Headern zu suchen . Wenn die Anfrage akzeptabel ist, wird die eigentliche Anfrage gesendet. Wenn Sie diese domänenübergreifende Aktion ausführen, müssen Sie sich lediglich damit befassen oder einen Weg finden, die Anfrage nicht domänenübergreifend zu gestalten. Aus diesem Grund wurde der jQuery-Fehler geschlossen, da er nicht behoben werden konnte. Dies ist beabsichtigt.

Im Gegensatz zu einfachen Anforderungen (siehe oben) senden "Preflighted" -Anforderungen zuerst eine HTTP-Anforderung mit der OPTIONS-Methode an die Ressource in der anderen Domäne, um festzustellen, ob die tatsächliche Anforderung sicher zu senden ist. Standortübergreifende Anforderungen werden auf diese Weise vorab ausgeführt, da sie Auswirkungen auf Benutzerdaten haben können. Insbesondere wird eine Anfrage vorab geflogen, wenn:

  • Es werden andere Methoden als GET, HEAD oder POST verwendet. Wenn POST zum Senden von Anforderungsdaten mit einem anderen Inhaltstyp als application / x-www-form-urlencoded, multipart / form-data oder text / plain verwendet wird, z. B. wenn die POST-Anforderung eine XML-Nutzlast an den Server sendet Wenn Sie application / xml oder text / xml verwenden, wird die Anforderung vorab ausgeführt.
  • Es werden benutzerdefinierte Header in der Anforderung festgelegt (z. B. verwendet die Anforderung einen Header wie X-PINGOTHER).

20
Benutzerdefinierte Header. Das ist wahrscheinlich das, was die Preflight-OPTIONS-Aufrufe auslöst.
Corey Ogburn

18

Aufgrund der Tatsache, dass die Anforderung nicht über den Standardport 80/443 gesendet wird, wird dieser Ajax-Aufruf automatisch als CORS-Anforderung (Cross-Origin Resource) betrachtet. Dies bedeutet, dass die Anforderung automatisch eine OPTIONS-Anforderung ausgibt, nach der gesucht wird CORS-Header auf der Seite des Servers / Servlets.

Dies geschieht auch dann, wenn Sie einstellen

crossOrigin: false;

oder auch wenn Sie es nicht tun.

Der Grund ist einfach das localhost != localhost:57124. Versuchen Sie, es nur localhostohne Port zu senden - es schlägt fehl, da das angeforderte Ziel nicht erreichbar ist. Beachten Sie jedoch, dass die Anforderung ohne die OPTIONS-Anforderung vor dem POST gesendet wird , wenn die Domänennamen gleich sind .


3

Ich stimme Kevin B zu, der Fehlerbericht sagt alles. Es hört sich so an, als würden Sie versuchen, domänenübergreifende Ajax-Anrufe zu tätigen. Wenn Sie nicht mit derselben Ursprungsrichtlinie vertraut sind, können Sie hier beginnen: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript .

Wenn dies kein domänenübergreifender Ajax-Aufruf sein soll, versuchen Sie, Ihre Ziel-URL relativ zu machen, und prüfen Sie, ob das Problem behoben ist. Wenn Sie wirklich verzweifelt in die JSONP schauen, aber Vorsicht, lauert Chaos. Wir können wirklich nicht viel mehr tun, um Ihnen zu helfen.


1
Unsere Systemstruktur kann ich nicht ändern. Die Verwendung eines anderen Ports ist eine Anforderung unserer Architektur. Ich habe die gleiche Herkunftsrichtlinie, dachte aber, dass das von uns implementierte CORS ausreicht. Scheinbar nicht.
Corey Ogburn

2
Wenn Ihr Server JSON-Antworten zurückgibt, können Sie die JSONP-Methode überprüfen. Verwenden Sie sie einfach verantwortungsbewusst.
Jgitter

1
Ich möchte nicht wirklich mit Ihnen streiten, aber JSONP verwendet Skript-Tags, um Daten aus einer anderen Domäne abzurufen, und sendet das Ergebnis dann an eine Rückruffunktion. Es ist viel schwieriger, wenn das Ergebnis nicht json ist.
Jgitter

1
Nein, es ist nicht viel schwieriger. Tatsächlich sollte die Antwort in keinem Fall ein gültiger JSON sein. Stattdessen sollte der Server Folgendes zurückgeben : callbackfunc(somedata). Wie Sie sehen können, ist dies kein gültiger JSON. Und somedatakann eine Zeichenfolge oder eine Zahl sein oder was auch immer Sie wollen.
Ray Nicholus

1
Ich benutze Postman und dort werden die Anforderungsmethoden korrekt gesendet (z. B. 'PUT', 'DELETE' usw.). Aber wenn ich versuche, es von meinem Code aus zu tun, sendet es sie immer mit der Anforderungsmethode OPTIONS. Ich habe keine Ahnung, wie Postman das kann.
ErwinGO

1

Wenn es möglich ist, übergeben Sie die Parameter durch reguläres GET / POST mit einem anderen Namen und lassen Sie Ihren serverseitigen Code damit umgehen.

Ich hatte ein ähnliches Problem mit meinem eigenen Proxy, um CORS zu umgehen, und ich bekam den gleichen Fehler wie POST-> OPTION in Chrome. Es war der AuthorizationHeader in meinem Fall ( "x-li-format"und "X-UserName"hier in Ihrem Fall). Am Ende habe ich ihn in einem Dummy-Format (z. B. AuthorizatinJackin GET) übergeben und den Code für meinen Proxy geändert, um ihn beim Aufrufen des Ziels in einen Header umzuwandeln . Hier ist es in PHP:

if (isset($_GET['AuthorizationJack'])) {
    $request_headers[] = "Authorization: Basic ".$_GET['AuthorizationJack'];
}

1

In meinem Fall rufe ich eine von AWS (API Gateway) gehostete API auf. Der Fehler trat auf, als ich versuchte, die API von einer anderen Domäne als der API-eigenen Domäne aufzurufen. Da ich der API-Besitzer bin, habe ich CORS für die Testumgebung aktiviert, wie in der Amazon-Dokumentation beschrieben .

In der Produktion tritt dieser Fehler nicht auf, da sich die Anforderung und die API in derselben Domäne befinden.

Ich hoffe, es hilft!


0

Wie von @Dark Falcon beantwortet , habe ich mich einfach darum gekümmert .

In meinem Fall verwende ich den Server node.js und erstelle eine Sitzung, falls diese nicht vorhanden ist. Da die OPTIONS-Methode nicht über die Sitzungsdetails verfügt, wurde für jede POST-Methodenanforderung eine neue Sitzung erstellt.

In meiner App-Routine zum Erstellen einer Sitzung, falls diese nicht vorhanden ist, habe ich nur eine Überprüfung hinzugefügt, um festzustellen, ob eine Methode vorhanden ist OPTIONS. Wenn ja, überspringen Sie einfach den Teil zum Erstellen einer Sitzung:

    app.use(function(req, res, next) {
        if (req.method !== "OPTIONS") {
            if (req.session && req.session.id) {
                 // Session exists
                 next();
            }else{
                 // Create session
                 next();
          }
        } else {
           // If request method is OPTIONS, just skip this part and move to the next method.
           next(); 
        }
    }


0

Erwägen Sie die Verwendung von Axios

axios.get( url,
{ headers: {"Content-Type": "application/json"} } ).then( res => {

  if(res.data.error) {

  } else { 
    doAnything( res.data )
  }

}).catch(function (error) {
   doAnythingError(error)
});

Ich hatte dieses Problem mit Fetch und Axios funktionierte perfekt.


5
Axios verwenden auch die ersten OPTIONEN
Skylin R

0

Ich bin auf ein sehr ähnliches Problem gestoßen. Ich habe fast einen halben Tag damit verbracht zu verstehen, warum in Firefox alles richtig funktioniert und in Chrome fehlschlägt. In meinem Fall lag es an doppelten (oder möglicherweise falsch eingegebenen) Feldern in meinem Anforderungsheader.


0

Verwenden Sie "Abrufen" anstelle von "XHR". Die Anforderung wird dann nicht vorbeleuchtet, selbst wenn sie domänenübergreifend ist.


-1
 $.ajax({
            url: '###',
            contentType: 'text/plain; charset=utf-8',
            async: false,
            xhrFields: {
                withCredentials: true,
                crossDomain: true,
                Authorization: "Bearer ...."
            },

            method: 'POST',

            data: JSON.stringify( request ),
            success: function (data) {
                console.log(data);
            }
        });

der contentType: 'text / plain; charset = utf-8 'oder einfach contentType:' text / plain 'funktioniert bei mir! Grüße!!


Was hat das überhaupt mit der Frage zu tun?
Corey Ogburn

HI, ich denke, dies löst das Problem im Titel. Mit diesem Inhaltstyp übergeben Sie die OPTIONS-Methode. Grüße
David Lopes

ContentType hat nichts mit der Methode zu tun.
Corey Ogburn

Ich weiß, was Sie sagen, aber probieren Sie es aus. Je nach Browser kann Ihr Inhaltstyp Ihre Anfrage beeinflussen und Ihre Methode ändern!
David Lopes
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.