Una richiesta POST CORS funziona da JavaScript semplice, ma perché non con jQuery?


88

Sto cercando di fare una richiesta di post Cross Origin e ho capito che funziona in modo semplice in JavaScriptquesto modo:

var request = new XMLHttpRequest();
var params = "action=something";
request.open('POST', url, true);
request.onreadystatechange = function() {if (request.readyState==4) alert("It worked!");};
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", params.length);
request.setRequestHeader("Connection", "close");
request.send(params);

Ma vorrei usarlo jQuery, ma non riesco a farlo funzionare. Questo è quello che sto provando:

$.ajax(url, {
    type:"POST",
    dataType:"json",
    data:{action:"something"}, 
    success:function(data, textStatus, jqXHR) {alert("success");},
    error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

Ciò si traduce in Fallimento. Se qualcuno sa perché jQuerynon funziona, faccelo sapere. Grazie.

(Sto usando jQuery1.5.1 e Firefox 4.0 e il mio server risponde con Access-Control-Allow-Originun'intestazione corretta )


Questa era la soluzione per me (usa XMLHttpRequest di Javascript) mentre affrontavo problemi di CORS con Ionic framework 3.
jeudyx

Risposte:


73

AGGIORNAMENTO: Come ha sottolineato TimK, questo non è più necessario con jquery 1.5.2. Ma se vuoi aggiungere intestazioni personalizzate o consentire l'uso di credenziali (nome utente, password o cookie, ecc.), Continua a leggere.


Penso di aver trovato la risposta! (4 ore e molte imprecazioni dopo)

//This does not work!!
Access-Control-Allow-Headers: *

Devi specificare manualmente tutte le intestazioni che accetti (almeno questo è stato il mio caso in FF 4.0 e Chrome 10.0.648.204).

Il metodo $ .ajax di jQuery invia l'intestazione "x-request-with" per tutte le richieste interdominio (penso sia l'unico interdominio).

Quindi l'intestazione mancante necessaria per rispondere alla richiesta OPTIONS è:

//no longer needed as of jquery 1.5.2
Access-Control-Allow-Headers: x-requested-with

Se stai passando intestazioni non "semplici", dovrai includerle nella tua lista (ne mando un'altra):

//only need part of this for my custom header
Access-Control-Allow-Headers: x-requested-with, x-requested-by

Quindi, per mettere tutto insieme, ecco il mio PHP:

// * wont work in FF w/ Allow-Credentials
//if you dont need Allow-Credentials, * seems to work
header('Access-Control-Allow-Origin: http://www.example.com');
//if you need cookies or login etc
header('Access-Control-Allow-Credentials: true');
if ($this->getRequestMethod() == 'OPTIONS')
{
  header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
  header('Access-Control-Max-Age: 604800');
  //if you need special headers
  header('Access-Control-Allow-Headers: x-requested-with');
  exit(0);
}

5
Nota che jQuery 1.5.2 ha cambiato il suo comportamento. Non aggiunge più un'intestazione "X-Requested-With", quindi questo potrebbe non essere più un problema. blog.jquery.com/2011/03/31/jquery-152-released (Bug 8423)
Magmatic

1
@TimK, hai ragione! Non ho notato che rilasciano 1.5.2. Detto questo, funziona anche se è necessario che sia pre-flight. Ho aggiornato la mia risposta.
Will Mason

Quindi, sono confuso. Hai finito per scrivere comunque uno script PHP intermedio? Quindi non devi preoccuparti di usare Ajax, giusto? Oppure mi sfugge qualcosa. Non esiste una soluzione solo JavaScript?
Elisabeth

1
@Elisabeth Questo metodo funziona solo se controlli la destinazione richiesta ... NON è uno script intermedio. È la parte superiore del nostro PHP della nostra posizione richiesta. Ha più senso?
Will Mason

2
Sì! grazie Will. Pensavo potessi controllare tutto dal lato client, ma sembra che tu abbia bisogno del controllo di entrambe le estremità.
Elisabeth

18

Un'altra possibilità è che l'impostazione dataType: jsonfa sì che JQuery invii l' Content-Type: application/jsonintestazione. Questa è considerata un'intestazione non standard da CORS e richiede una richiesta di verifica preliminare CORS. Quindi alcune cose da provare:

1) Prova a configurare il tuo server per inviare le risposte corrette di preflight. Questo sarà sotto forma di intestazioni aggiuntive come Access-Control-Allow-Methodse Access-Control-Allow-Headers.

2) Elimina l' dataType: jsonimpostazione. JQuery dovrebbe richiedere Content-Type: application/x-www-form-urlencodedper impostazione predefinita, ma per sicurezza, puoi sostituire dataType: jsonconcontentType: 'application/x-www-form-urlencoded'


Grazie per le idee. Ho provato a non impostare dataType e impostarlo per essere application/x-www-form-urlencodede pari text/plain. E ho provato ad aggiungere un'intestazione di risposta di Access-Control-Allow-Methods "POST, GET, OPTIONS"Nothing ha funzionato.
Magmatic

Puoi guardare nella console degli errori JavaScript (o nella console di Firebug) e vedere se ci sono errori durante la richiesta? Inoltre, se sai come usare Wireshark, puoi usarlo per vedere le effettive richieste HTTP in corso.
monsur

1
"Un'altra possibilità è che l'impostazione dataType: json fa sì che JQuery invii l'intestazione Content-Type: application / json" - Questo non accade. dataTypeinfluenza l' Acceptintestazione della richiesta ma non l' Content-Typeintestazione della richiesta.
Quentin

9

Stai inviando "params" in js: request.send(params);

ma "dati" in jquery ". I dati sono definiti ?: data:data,

Inoltre, hai un errore nell'URL:

$.ajax( {url:url,
         type:"POST",
         dataType:"json",
         data:data, 
         success:function(data, textStatus, jqXHR) {alert("success");},
         error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

Stai mescolando la sintassi con quella di $ .post


Aggiornamento : stavo cercando su Google in base alla risposta di monsur e ho scoperto che è necessario aggiungere Access-Control-Allow-Headers: Content-Type(di seguito è riportato il paragrafo completo)

http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/

Come funziona CORS

CORS funziona in modo molto simile al file crossdomain.xml di Flash. Fondamentalmente, il browser invierà una richiesta interdominio a un servizio, impostando l'origine dell'intestazione HTTP sul server richiedente. Il servizio include alcune intestazioni come Access-Control-Allow-Origin per indicare se tale richiesta è consentita.

Per i gestori di connessione BOSH è sufficiente specificare che sono consentite tutte le origini, impostando il valore di Access-Control-Allow-Origin su *. Anche l'intestazione Content-Type deve essere inserita nella white list nell'intestazione Access-Control-Allow-Headers.

Infine, per alcuni tipi di richieste, incluse le richieste del gestore connessione BOSH, il controllo delle autorizzazioni verrà pre-eseguito. Il browser eseguirà una richiesta OPTIONS e si aspetterà di recuperare alcune intestazioni HTTP che indicano quali origini sono consentite, quali metodi sono consentiti e quanto tempo durerà questa autorizzazione. Ad esempio, ecco cosa le patch Punjab ed ejabberd che ho restituito per OPTIONS:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type 
Access-Control-Max-Age: 86400

1
Scusate. Sì. var data = {action:"something"}
Magmatic

Puoi confrontare la sintassi per entrambe le funzioni qui: api.jquery.com/jQuery.post
Aleadam

L'ho appena provato con l'URL nelle impostazioni, ma lo stesso problema. La funzione .ajax può accettarla in entrambi i casi.
Magmatic

Avevo già due di quelle intestazioni. Ho aggiunto gli altri due. Ancora "fallimento" con jQuery. Il semplice javascript funziona ancora.
Magmatic

L'ultima cosa a cui riesco a pensare è usare api.jquery.com/jQuery.ajaxSetup per impostare jQuery.ajaxSetup({'beforeSend': function(xhr) {xhr.setRequestHeader(string, string)}})e giocare con le diverse intestazioni inviate (un esempio per i binari qui: railscasts.com/episodes/136-jquery )
Aleadam

1

Cors cambia il metodo di richiesta prima che sia fatto, da POST a OPTIONS, quindi i dati del tuo post non verranno inviati. Il modo in cui ha funzionato per gestire questo problema di cors, è eseguire la richiesta con ajax, che non supporta il metodo OPTIONS. codice di esempio:

        $.ajax({
            type: "POST",
            crossdomain: true,
            url: "http://localhost:1415/anything",
            dataType: "json",
            data: JSON.stringify({
                anydata1: "any1",
                anydata2: "any2",
            }),
            success: function (result) {
                console.log(result)
            },
            error: function (xhr, status, err) {
                console.error(xhr, status, err);
            }
        });

con queste intestazioni sul server c #:

                    if (request.HttpMethod == "OPTIONS")
                    {
                          response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
                          response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
                          response.AddHeader("Access-Control-Max-Age", "1728000");
                    }
                    response.AppendHeader("Access-Control-Allow-Origin", "*");

-2

Modifica il tuo Jquery nel modo seguente:

$.ajax({
            url: someurl,
            contentType: 'application/json',
            data: JSONObject,
            headers: { 'Access-Control-Allow-Origin': '*' }, //add this line
            dataType: 'json',
            type: 'POST',                
            success: function (Data) {....}
});

Perché dovrei voler rendere sincrone le mie chiamate Ajax !?
Radko Dinev

contentType: 'application/json', data: JSONObject,- Il server non si aspetta JSON, quindi inviare JSON non avrebbe senso. Inoltre, non esiste un oggetto JSON .
Quentin

1
headers: { 'Access-Control-Allow-Origin': '*' }, //add this line- Non farlo mai . Access-Control-Allow-Originè un'intestazione di risposta , non un'intestazione di richiesta. Nella migliore delle ipotesi questo non farà nulla. Nel peggiore dei casi, convertirà la richiesta da una semplice richiesta a una richiesta di preflight che rende sempre più difficile gestirla sul server.
Quentin
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.