web-dev-qa-db-fra.com

Une demande CORS POST) fonctionne à partir de javascript simple, mais pourquoi pas avec jQuery?

J'essaie de faire une demande de publication Cross Origin, et je l'ai obtenue en Javascript simple comme ceci:

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);

Mais je voudrais utiliser jQuery, mais je ne peux pas le faire fonctionner. C'est ce que j'essaye:

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

Cela entraîne un échec. Si quelqu'un sait pourquoi jQuery ne fonctionne pas, merci de nous le faire savoir. Merci.

(J'utilise jQuery 1.5.1 et Firefox 4.0, et mon serveur répond avec un en-tête approprié Access-Control-Allow-Origin)

82
Magmatic

UPDATE: Comme TimK l'a fait remarquer, cela n'est plus nécessaire avec jquery 1.5.2. Toutefois, si vous souhaitez ajouter des en-têtes personnalisés ou autoriser l'utilisation d'informations d'identification (nom d'utilisateur, mot de passe ou cookies, etc.), continuez.


Je pense avoir trouvé la réponse! (4 heures et beaucoup de malédiction plus tard)

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

Vous devez spécifier manuellement tous les en-têtes que vous accepterez (du moins c'était le cas pour moi dans FF 4.0 & Chrome 10.0.648.204).

la méthode $ .ajax de jQuery envoie l'en-tête "x-demandé-avec" pour toutes les requêtes entre domaines (je pense que c'est le seul domaine).

L'en-tête manquant nécessaire pour répondre à la demande OPTIONS est donc:

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

Si vous passez des en-têtes non "simples", vous devrez les inclure dans votre liste (j'en envoie un de plus):

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

Donc pour résumer, voici mon 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);
}
71
Will Mason

Une autre possibilité est que le paramètre dataType: json provoque l'envoi par JQuery du Content-Type: application/json entête. Ceci est considéré comme un en-tête non standard par CORS et nécessite une demande de contrôle en amont de CORS. Donc, quelques choses à essayer:

1) Essayez de configurer votre serveur pour envoyer les réponses de contrôle en amont appropriées. Ce sera sous la forme d'en-têtes supplémentaires comme Access-Control-Allow-Methods et Access-Control-Allow-Headers.

2) Lâchez le dataType: json réglage. JQuery devrait demander Content-Type: application/x-www-form-urlencoded _ par défaut, mais pour être sûr, vous pouvez remplacer dataType: json avec contentType: 'application/x-www-form-urlencoded'

16
monsur

Vous envoyez "params" en js: request.send(params);

mais "données" dans jquery ". Des données sont-elles définies ?: data:data,

En outre, vous avez une erreur dans l'URL:

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

Vous mélangez la syntaxe avec celle de $ .post


Mise à jour : J'étais en train de chercher sur Google en me basant sur la réponse de monsur et j'ai trouvé qu'il fallait ajouter Access-Control-Allow-Headers: Content-Type _ (ci-dessous est le paragraphe complet)

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

Comment fonctionne la SCRO

CORS fonctionne de manière très similaire au fichier crossdomain.xml de Flash. Fondamentalement, le navigateur envoie une demande interdomaine à un service en définissant l’en-tête HTTP Origin sur le serveur demandeur. Le service comprend quelques en-têtes tels que Access-Control-Allow-Origin pour indiquer si une telle demande est autorisée.

Pour les gestionnaires de connexions BOSH, il suffit de spécifier que toutes les origines sont autorisées en définissant la valeur de Access-Control-Allow-Origin sur *. L'en-tête Content-Type doit également figurer sur la liste blanche dans l'en-tête Access-Control-Allow-Headers.

Enfin, pour certains types de demandes, y compris les demandes du gestionnaire de connexions BOSH, le contrôle des autorisations sera effectué préalablement. Le navigateur fera une demande OPTIONS et s’attendra à récupérer des en-têtes HTTP indiquant les origines autorisées, les méthodes autorisées et la durée de cette autorisation. Par exemple, voici ce que les patchs Punjab et ejabberd que j’ai renvoyés pour OPTIONS:

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

Cors change la méthode de requête avant que celle-ci ne soit terminée, de POST à OPTIONS, vos données de publication ne seront donc pas envoyées. La façon dont a fonctionné cette question cors consiste à exécuter la demande avec ajax, qui ne supporte pas la méthode OPTIONS, exemple de code:

        $.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);
            }
        });

avec ces en-têtes sur le serveur 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", "*");