web-dev-qa-db-fra.com

Pourquoi est-ce que je reçois une demande OPTIONS au lieu d'une demande GET?

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script>
$.get("http://example.com/", function(data) {
     alert(data);
});
</script>

il envoie une requête OPTIONS à cette URL, puis le rappel n'est jamais appelé avec quoi que ce soit. 

Quand ce n'est pas inter-domaine, cela fonctionne bien.

JQuery ne devrait-il pas se contenter d’appeler avec un nœud <script> puis faire le rappel lorsqu’il est chargé? Je comprends que je ne pourrai pas obtenir le résultat (puisqu'il s'agit d'un domaine croisé), mais ce n'est pas grave; Je veux juste que l'appel soit passé. Est-ce un bug ou est-ce que je fais quelque chose de mal?

246
Paul Tarjan
85
Paul Tarjan

Selon MDN ,

Demandes de contrôle en amont

Contrairement aux demandes simples (voir ci-dessus), les demandes "pré-contrôlées" sont les premières envoyer un en-tête de requête HTTP OPTIONS à la ressource de l'autre domaine, afin de déterminer si la demande réelle est sûre pour envoyer. Les requêtes intersites sont pré-contrôlées comme ceci car elles peuvent avoir des implications sur les données de l'utilisateur. En particulier, une demande est contrôle en amont si:

  • Il utilise des méthodes autres que GET ou POST. De plus, si POST est utilisé pour envoyer demander des données avec un type de contenu autre que application/x-www-form-urlencoded, multipart/form-data ou text/plain, par exemple. si la demande POST envoie une charge XML au serveur à l'aide de application/xml ou text/xml, la demande est contrôlée en amont. 
  • Il définit des en-têtes personnalisés dans la demande (par exemple, la demande utilise un en-tête tel que X-PINGOTHER).
224
arturgrigor

Si vous essayez de POSTER

Assurez-vous de JSON.stringify vos données de formulaire et envoyez-le en tant que text/plain.

<form id="my-form" onSubmit="return postMyFormData();">
    <input type="text" name="name" placeholder="Your Name" required>
    <input type="email" name="email" placeholder="Your Email" required>
    <input type="submit" value="Submit My Form">
</form>

function postMyFormData() {

    var formData = $('#my-form').serializeArray();
    formData = formData.reduce(function(obj, item) {
        obj[item.name] = item.value;
        return obj;
    }, {});
    formData = JSON.stringify(formData);

    $.ajax({
        type: "POST",
        url: "https://website.com/path",
        data: formData,
        success: function() { ... },
        dataType: "text",
        contentType : "text/plain"
    });
}
4
Derek Soike

Je ne crois pas que jQuery fera naturellement une requête JSONP quand une URL comme celle-ci lui est donnée. Cependant, il fera une demande JSONP quand vous lui direz quel argument utiliser pour un rappel:

$.get("http://metaward.com/import/http://metaward.com/u/ptarjan?jsoncallback=?", function(data) {
     alert(data);
});

Il appartient entièrement au script de destination d'utiliser cet argument (qui ne doit pas nécessairement s'appeler "jsoncallback"). Dans ce cas, la fonction ne sera jamais appelée. Mais, puisque vous avez indiqué que vous souhaitiez simplement que le script de metaward.com soit exécuté, cela le ferait.

2
VoteyDisciple

J'ai eu le même problème. Mon correctif consistait à ajouter des en-têtes à mon script PHP, qui ne sont présents que dans l'environnement dev.

Cela permet aux requêtes interdomaines:

header("Access-Control-Allow-Origin: *");

Cela indique à la demande de contrôle en amont que le client peut envoyer les en-têtes de son choix:

header("Access-Control-Allow-Headers: *");

De cette façon, il n'est pas nécessaire de modifier la demande.

Si votre base de données dev contient des données sensibles susceptibles d’être divulguées, réfléchissez-y à deux fois.

1
fivebit

Remplacez simplement "application/json" par "text/plain" et n'oubliez pas le JSON.stringify (demande):

var request = {Company: sapws.dbName, UserName: username, Password: userpass};
    console.log(request);
    $.ajax({
        type: "POST",
        url: this.wsUrl + "/Login",
        contentType: "text/plain",
        data: JSON.stringify(request),

        crossDomain: true,
    });
1
David Lopes

En fait, les requêtes interdomaines AJAX (XMLHttp) ne sont pas autorisées pour des raisons de sécurité (pensez à extraire une page Web "restreinte" du côté client et à la renvoyer au serveur - il s'agirait d'un problème de sécurité ).

Les seules solutions de contournement sont les rappels. C’est-à-dire: créer un nouvel objet de script et faire pointer la src vers le JavaScript de fin d’application, c’est-à-dire un rappel avec des valeurs JSON (myFunction ({data})), myFunction est une fonction qui manipule les données (par exemple, les stockant). dans une variable).

1
Adrián Navarro

Dans mon cas, le problème n'était pas lié à CORS puisque j'émettais un jQuery POST sur le même serveur Web. Les données étaient JSON mais j'avais omis le paramètre dataType: 'json'. 

Je n'avais pas (ni ajouté) de paramètre contentType, comme indiqué dans la réponse de David Lopes ci-dessus.

0
GarDavis

J'ai pu résoudre le problème à l'aide des en-têtes suivants

Access-Control-Allow-Origin
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
Access-Control-Allow-Methods

Si vous êtes sur Nodejs, voici le code que vous pouvez copier/coller.

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin','*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH');
  next();
});
0
obai

On dirait que Firefox et Opera (également testés sur mac) n’aiment pas le caractère croisé de ce domaine (mais Safari va très bien avec cela). 

Vous devrez peut-être appeler un code côté serveur local pour courber la page distante. 

0
helloandre