IE9 jQuery AJAX avec CORS renvoie «L'accès est refusé»

123

Ce qui suit fonctionne dans tous les navigateurs sauf IE (je teste dans IE 9).

jQuery.support.cors = true;
...
        $.ajax(
            url + "messages/postMessageReadByPersonEmail",
            {
                crossDomain: true,
                data: {
                    messageId       : messageId,
                    personEmail     : personEmail
                },
                success: function() {
                    alert('marked as read');
                },
                error: function(a,b,c) {
                    alert('failed');
                },
                type: 'post'
            }
        );

J'ai une autre fonction qui utilise dataType: 'jsonp', mais je n'ai besoin d'aucune donnée renvoyée sur cet appel AJAX. Mon dernier recours sera de renvoyer du jibberish enveloppé dans JSONP juste pour le faire fonctionner.

Des idées pour lesquelles IE se trompe avec une requête CORS qui ne renvoie aucune donnée?

Garrett
la source
Étant donné qu'aucune des réponses proposées n'a fonctionné pour moi (je devais également passer des cookies dans la requête CORS, ce qui est un non-non lors de l'utilisation de XDomainRequest), voici une solution de contournement: blog.gauffin.org/2014/04 / ... . Proxying à la rescousse! : p
wimvds

Réponses:

150

Il s'agit d'un bogue connu avec jQuery. L'équipe jQuery n'a "pas l'intention de prendre en charge cela dans le noyau et est mieux adaptée en tant que plugin." (Voir ce commentaire ). IE ne pas utiliser le XMLHttpRequest , mais un objet autre nom XDomainRequest .

Il existe un plugin disponible pour prendre en charge cela dans jQuery, qui peut être trouvé ici : https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

EDIT La fonction $.ajaxTransportenregistre une usine de transport. Un transporteur est utilisé en interne par $.ajaxpour effectuer des demandes. Par conséquent, je suppose que vous devriez pouvoir appeler $.ajaxcomme d'habitude. Vous $.ajaxtrouverez ici des informations sur les transporteurs et l'extension .

En outre, une version peut-être meilleure de ce plugin peut être trouvée ici .

Deux autres remarques:

  1. L'objet XDomainRequest a été introduit à partir d'IE8 et ne fonctionnera pas dans les versions ci-dessous.
  2. À partir d'IE10, CORS sera pris en charge à l'aide d'un XMLHttpRequest normal .

Edit 2: problème http vers https

Les demandes doivent être ciblées sur le même schéma que la page d'hébergement

Cette restriction signifie que si votre page AJAX se trouve sur http://example.com , votre URL cible doit également commencer par HTTP. De même, si votre page AJAX se trouve sur https://example.com , votre URL cible doit également commencer par HTTPS.

Source: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

Dennisg
la source
12
La "meilleure version" du plugin est innée; Je viens de l'inclure dans ma page et cela a automatiquement corrigé mes appels $ .ajax :) En supposant, bien sûr, que vous ayez tous les en-têtes nécessaires en place.
Kato
5
Pour ajouter à la réponse de dennisg, xdr.js a un bogue - le callback ajaxTransport ne sera pas appelé tel quel. J'ai dû le changer conformément à stackoverflow.com/questions/12481560/... (ajouté "+ *" comme premier argument de l'appel ajaxTransport).
Volodymyr Otryshko
4
jQuery.XDomainRequest.js s'assure que la page actuelle et la page distante sont à la fois http ou https. Cela signifie-t-il que vous ne pouvez pas appeler une API https à partir d'une page http?
Aaron
2
Il est à noter que le code qui était lié sur le dépôt github moonscripts est une ancienne version qui ne fonctionne pas. Assurez-vous d'obtenir la dernière version sur: raw.github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest/…
Clintm
3
@Aaron, en ajoutant au commentaire de @ HariKaramSingh: changer les protocoles ( httpvers https), les domaines ( google.comvers bing.com), les sous-domaines ( mail.google.comvers maps.google.com) ou les protocoles ( google.com:80- le port par défaut vers google.com:8080) déclenchera tous une requête "interdomaine". Fondamentalement, tout ce qui précède le premier /dans votre URL doit être identique.
allicarn
62

En me basant sur la réponse acceptée par @dennisg, j'ai réussi cela en utilisant jQuery.XDomainRequest.js par MoonScript.

Le code suivant a fonctionné correctement dans Chrome, Firefox et IE10, mais a échoué dans IE9. J'ai simplement inclus le script et il fonctionne maintenant automatiquement dans IE9. (Et probablement 8, mais je ne l'ai pas testé.)

var displayTweets = function () {
    $.ajax({
        cache: false,
        type: 'GET',
        crossDomain: true,
        url: Site.config().apiRoot + '/Api/GetTwitterFeed',
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        success: function (data) {
            for (var tweet in data) {
                displayTweet(data[tweet]);
            }
        }
    });
};
JackMorrissey
la source
3
Le plugin jQuery.XDomainRequest.js était exactement ce dont j'avais besoin! Je n'ai pas pu faire fonctionner le plugin iexhr.js pour les requêtes derrière l'authentification de base HTTP, mais XDomainRequest a fonctionné comme un charme!
James Ford
Cela a fonctionné pour moi. Je n'avais pas besoin de Site.config (). ApiRoot + (ce que je suppose est pour twitter ....) Mais cela fonctionne très bien, merci de faire cela.
Nicholas Decker
@NicholasDecker Site.config (). ApiRoot était juste un code spécifique à l'implémentation pour obtenir l'URL racine de l'API, rien d'universel ou de fantaisie. Heureux que cela ait aidé!
JackMorrissey
J'espérais que cela fonctionnerait pour moi, mais j'essaye de POSTER. me demande si c'est le problème pour moi.
Jack Marchetti
1
@cracker Avez-vous uniquement des problèmes avec POST? Vérifiez que le script se charge après jQuery et que votre appel correspond à la documentation de MoonScript.
JackMorrissey
16

Des instructions complètes sur la façon de procéder à l'aide du plugin "jQuery-ajaxTransport-XDomainRequest" peuvent être trouvées ici: https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest#instructions

Ce plugin est activement pris en charge et gère HTML, JSON et XML. Le fichier est également hébergé sur CDNJS, vous pouvez donc déposer directement le script dans votre page sans configuration supplémentaire: http://cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.1/jquery.xdomainrequest .min.js

MoonScript
la source
1
Cela a très bien fonctionné. Incroyable que ce problème existe dans jQuery mais ... Merci!
Cymen
3

Le problème est que IE9 et les versions antérieures ne prennent pas en charge CORS. XDomainRequest ne prend en charge que GET / POST et le text/plaintype conten comme décrit ici: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

Donc, si vous souhaitez utiliser tous les verbes HTTP et / ou json, etc., vous devez utiliser une autre solution. J'ai écrit un proxy qui rétrogradera gracieusement vers le proxy si IE9 ou moins est utilisé. Vous n'avez pas du tout à modifier votre code si vous utilisez ASP.NET.

La solution est en deux parties. Le premier est un script jquery qui se connecte au traitement jQuery ajax. Il appellera automatiquement le serveur Web si une requête crossDomain est effectuée et que le navigateur est IE:

$.ajaxPrefilter(function (options, originalOptions, jqXhr) {
    if (!window.CorsProxyUrl) {
        window.CorsProxyUrl = '/corsproxy/';
    }
    // only proxy those requests
    // that are marked as crossDomain requests.
    if (!options.crossDomain) {
        return;
    }

    if (getIeVersion() && getIeVersion() < 10) {
        var url = options.url;
        options.beforeSend = function (request) {
            request.setRequestHeader("X-CorsProxy-Url", url);
        };
        options.url = window.CorsProxyUrl;
        options.crossDomain = false;
    }
});

Dans votre serveur Web, vous devez recevoir la requête, obtenir la valeur de l'en-tête http X-CorsProxy-Url et faire une requête HTTP et enfin renvoyer le résultat.

Mon article de blog: http://blog.gauffin.org/2014/04/how-to-use-cors-requests-in-internet-explorer-9-and-below/

Jgauffin
la source
1

Je viens de faire toutes les requêtes JSONP car c'était la seule solution pour tous nos navigateurs supportés (IE7 + et les habitués). Remarquez que votre réponse fonctionne techniquement pour IE9, vous avez donc la bonne réponse.

Garrett
la source
2
Juste une note à toute personne ayant ce problème - dans ce cas, si vous avez une exigence <= IE7 et que vous n'avez pas de contrôle sur le serveur (par exemple, vous ne pouvez pas le faire prendre en charge les balises de script GET + avec JSONP), votre Le meilleur pari est un serveur middleware léger qui traduit l'appel JSONP en un POST et renvoie la réponse du serveur de boîte noire à l'utilisateur.
mikermcneil
1

En vous basant sur la solution de MoonScript, vous pouvez essayer ceci à la place:

https://github.com/intuit/xhr-xdr-adapter/blob/master/src/xhr-xdr-adapter.js

L'avantage est que puisqu'il s'agit d'une solution de niveau inférieur, elle activera CORS (dans la mesure du possible) sur IE 8/9 avec d'autres frameworks, pas seulement avec jQuery. Je l'ai utilisé avec succès avec AngularJS, ainsi qu'avec jQuery 1.x et 2.x.

Yanni
la source
0

Pour résoudre ce problème, vérifiez également si vous avez inclus des .js dans votre fichier ajax appelé: J'ai reçu une erreur d'accès refusé en incluant shadowbox.js dans mon ajax.php

hacklover
la source
0

J'étais en train de tester un service Web CORS sur ma machine de développement et recevais le message d'erreur "Accès refusé" uniquement dans IE. Firefox et Chrome ont bien fonctionné. Il s'avère que cela a été causé par mon utilisation de localhost dans l'appel ajax! Donc, l'URL de mon navigateur était quelque chose comme:

http: //my_computer.my_domain.local/CORS_Service/test.html

et mon appel ajax à l'intérieur de test.html ressemblait à quelque chose comme:

//fails in IE 
$.ajax({
  url: "http://localhost/CORS_Service/api/Controller",
  ...
});

Tout a fonctionné une fois que j'ai changé l'appel ajax pour utiliser l'adresse IP de mon ordinateur au lieu de localhost.

//Works in IE
$.ajax({
  url: "http://192.168.0.1/CORS_Service/api/Controller",
  ...
});

L'onglet "Réseau" de la fenêtre des outils de développement IE affiche également la requête OPTIONS de contrôle en amont CORS suivie de XMLHttpRequest GET, ce que je m'attendais à voir.

jwill212
la source
0

Mise à jour début 2015. xDomain est une bibliothèque largement utilisée pour prendre en charge CORS sur IE9 avec un codage supplémentaire limité.

https://github.com/jpillora/xdomain

Bernard
la source
-1

Remarque - Remarque

n'utilisez pas " http://www.domain.xxx " ou " http: // localhost / " ou "IP >> 127.0.0.1" pour l'URL en ajax. utilisez uniquement le chemin (répertoire) et le nom de la page sans adresse.

faux état:

var AJAXobj = createAjax();
AJAXobj.onreadystatechange = handlesAJAXcheck;
AJAXobj.open('POST', 'http://www.example.com/dir/getSecurityCode.php', true);
AJAXobj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
AJAXobj.send(pack);

état vrai:

var AJAXobj = createAjax();
AJAXobj.onreadystatechange = handlesAJAXcheck;
AJAXobj.open('POST', 'dir/getSecurityCode.php', true);   // <<--- note
AJAXobj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
AJAXobj.send(pack);
Ali Bagheri
la source