IE9 jQuery AJAX with CORS zwraca „Access is denied”

123

Poniższe działa we wszystkich przeglądarkach oprócz IE (testuję w 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'
            }
        );

Mam inną funkcję, która używa dataType: 'jsonp', ale nie potrzebuję żadnych danych zwracanych w tym wywołaniu AJAX. Moją ostatnią deską ratunku będzie zwrócenie jakiegoś jibberisha zapakowanego w JSONP, aby to zadziałało.

Jakieś pomysły, dlaczego IE spieprzyło żądanie CORS, które nie zwraca żadnych danych?

Garrett
źródło
Ponieważ żadna z proponowanych odpowiedzi nie zadziałała dla mnie (musiałem również przekazać pliki cookie do żądania CORS, co jest nie-nie przy korzystaniu z XDomainRequest), oto obejście: blog.gauffin.org/2014/04/ ... . Proxing na ratunek! : p
wimvds

Odpowiedzi:

150

To znany błąd dotyczący jQuery. Zespół jQuery „nie planuje obsługi tego w rdzeniu i lepiej nadaje się jako wtyczka”. (Zobacz ten komentarz ). IE nie używa XMLHttpRequest , ale alternatywny obiekt o nazwie XDomainRequest .

Dostępna jest wtyczka do obsługi tego w jQuery, którą można znaleźć tutaj : https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

EDYCJA Funkcja $.ajaxTransportrejestruje fabrykę transportera. Transporter jest używany wewnętrznie przez firmę $.ajaxdo wykonywania zleceń. Dlatego zakładam, że powinieneś móc zadzwonić $.ajaxjak zwykle. Informacje o transporterach i przedłużeniach $.ajaxmożna znaleźć tutaj .

Również prawdopodobnie lepszą wersję tej wtyczki można znaleźć tutaj .

Dwie inne uwagi:

  1. Obiekt XDomainRequest został wprowadzony z IE8 i nie będzie działał w poniższych wersjach.
  2. Z IE10 CORS będzie obsługiwany przy użyciu normalnego XMLHttpRequest .

Edycja 2: problem z http do https

Żądania muszą być kierowane na ten sam schemat, co strona hostująca

To ograniczenie oznacza, że ​​jeśli Twoja strona AJAX znajduje się pod adresem http://example.com , docelowy adres URL również musi zaczynać się od HTTP. Podobnie, jeśli Twoja strona AJAX znajduje się pod adresem https://example.com , docelowy adres URL również musi zaczynać się od HTTPS.

Źródło: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

dennisg
źródło
12
„Lepsza wersja” wtyczki jest wrodzona; Właśnie umieściłem go na mojej stronie i automagicznie naprawiłem moje wywołania $ .ajax :) Zakładając oczywiście, że masz wszystkie niezbędne nagłówki na swoich miejscach.
Kato
5
Aby dodać do odpowiedzi dennisg, xdr.js ma błąd - wywołanie zwrotne ajaxTransport nie zostanie wywołane tak, jak jest. Musiałem to zmienić zgodnie ze stackoverflow.com/questions/12481560/… (dodano „+ *” jako pierwszy argument wywołania ajaxTransport).
Volodymyr Otryshko
4
jQuery.XDomainRequest.js upewnia się, że bieżąca strona i strona zdalna to zarówno http, jak i https. Czy to oznacza, że ​​nie możesz wywołać interfejsu API https ze strony http?
Aaron
2
Warto zauważyć, że kod, do którego był link w repozytorium github moonscripts, jest starą wersją, która nie działa. Pamiętaj, aby pobrać najnowszą wersję pod adresem: raw.github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest/ ...
Clintm
3
@Aaron, dodając do komentarza @ HariKaramSingh: zmiana protokołów ( httpna https), domen ( google.comna bing.com), subdomen ( mail.google.comna maps.google.com) lub protokołów ( google.com:80- domyślny port na google.com:8080) spowoduje wysłanie żądania „międzydomenowego”. Zasadniczo wszystko przed pierwszą /w adresie URL musi być identyczne.
allicarn
62

Opierając się na zaakceptowanej odpowiedzi @dennisg, udało mi się to pomyślnie osiągnąć przy użyciu jQuery.XDomainRequest.js autorstwa MoonScript.

Poniższy kod działał poprawnie w Chrome, Firefox i IE10, ale nie działał w IE9. Po prostu dołączyłem skrypt i teraz automagicznie działa w IE9. (I prawdopodobnie 8, ale nie testowałem tego.)

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
źródło
3
Wtyczka jQuery.XDomainRequest.js była dokładnie tym, czego potrzebowałem! Nie mogłem sprawić, by wtyczka iexhr.js działała dla żądań za podstawowym uwierzytelnianiem HTTP, ale XDomainRequest działało jak cudowne!
James Ford
To zadziałało dla mnie. Nie potrzebowałem Site.config (). ApiRoot + (który zakładam, że jest przeznaczony dla Twittera…) Ale działa świetnie, dzięki za zrobienie tego.
Nicholas Decker
@NicholasDecker Site.config (). ApiRoot był po prostu kodem implementacyjnym, aby uzyskać główny adres URL API, nic uniwersalnego ani wyszukanego. Cieszę się, że pomogło!
JackMorrissey
Miałem nadzieję, że to zadziała, ale próbuję POST. Zastanawiam się, czy to jest dla mnie problem.
Jack Marchetti
1
@cracker Czy masz problemy tylko z POST? Dokładnie sprawdź, czy skrypt ładuje się po jQuery, a Twoje wywołanie jest zgodne z dokumentacją MoonScript.
JackMorrissey
16

Pełne instrukcje, jak to zrobić za pomocą wtyczki „jQuery-ajaxTransport-XDomainRequest”, można znaleźć tutaj: https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest#instructions

Ta wtyczka jest aktywnie obsługiwana i obsługuje HTML, JSON i XML. Plik jest również hostowany na CDNJS, więc możesz bezpośrednio upuścić skrypt na swoją stronę bez dodatkowej konfiguracji: http://cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.1/jquery.xdomainrequest .min.js

MoonScript
źródło
1
To działało świetnie - naprawa. Niewiarygodne, że ten problem istnieje w jQuery, ale ... Dziękuję!
Cymen
3

Problem polega na tym, że IE9 i starsze nie obsługują CORS. XDomainRequest obsługuje tylko GET / POST i text/plaintyp zawartości, jak opisano tutaj: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

Więc jeśli chcesz używać wszystkich czasowników HTTP i / lub json itp., Musisz użyć innego rozwiązania. Napisałem proxy, które z wdziękiem przejdzie na serwer proxy, jeśli używany jest IE9 lub mniej. Nie musisz w ogóle zmieniać kodu, jeśli używasz ASP.NET.

Rozwiązanie jest w dwóch częściach. Pierwszym jest skrypt jquery, który podpina się do przetwarzania jQuery ajax. Automatycznie wywoła serwer sieciowy, jeśli zostanie wysłane żądanie crossDomain, a przeglądarka to 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;
    }
});

Na swoim serwerze WWW musisz odebrać żądanie, pobrać wartość z nagłówka X-CorsProxy-Url http, wykonać żądanie HTTP i na koniec zwrócić wynik.

Mój post na blogu: http://blog.gauffin.org/2014/04/how-to-use-cors-requests-in-internet-explorer-9-and-below/

jgauffin
źródło
1

Właśnie wykonałem wszystkie żądania JSONP, ponieważ było to jedyne rozwiązanie dla wszystkich naszych obsługiwanych przeglądarek (IE7 + i zwykłych). Pamiętaj, że twoja odpowiedź technicznie działa dla IE9, więc masz poprawną odpowiedź.

Garrett
źródło
2
Tylko uwaga dla każdego, kto ma ten problem - w tym przypadku, jeśli masz wymagania <= IE7 i nie masz kontroli nad serwerem (np. Nie możesz sprawić, by obsługiwał znaczniki GET + script w / JSONP) best bet to lekki serwer pośredniczący, który tłumaczy wywołanie JSONP na POST i przesyła odpowiedź z serwera czarnej skrzynki z powrotem do użytkownika.
mikermcneil
1

Opierając się na rozwiązaniu MoonScript, możesz spróbować tego:

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

Zaletą jest to, że ponieważ jest to rozwiązanie niższego poziomu, umożliwi CORS (w miarę możliwości) w IE 8/9 z innymi frameworkami, nie tylko z jQuery. Odniosłem sukces, używając go z AngularJS, a także z jQuery 1.x i 2.x.

yanni
źródło
0

Aby rozwiązać ten problem, sprawdź również, czy masz dołączony plik .js do pliku Ajax o nazwie: Otrzymałem błąd odmowy dostępu podczas dołączania shadowbox.js w moim pliku ajax.php

hacklover
źródło
0

Testowałem usługę internetową CORS na moim komputerze deweloperskim i otrzymywałem komunikat o błędzie „Odmowa dostępu” tylko w przeglądarce IE. Firefox i Chrome działały dobrze. Okazuje się, że było to spowodowane moim użyciem localhost w wywołaniu Ajax! Więc adres URL mojej przeglądarki wyglądał następująco:

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

a moje wywołanie Ajax w pliku test.html wyglądało tak:

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

Wszystko działało, gdy zmieniłem wywołanie Ajax tak, aby używał adresu IP mojego komputera zamiast lokalnego hosta.

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

Zakładka „Sieć” w oknie narzędzi deweloperskich IE pokazuje również żądanie CORS Preflight OPTIONS, po którym następuje XMLHttpRequest GET, co jest dokładnie tym, czego się spodziewałem.

jwill212
źródło
0

Aktualizacja z początku 2015 r. XDomain to powszechnie używana biblioteka obsługująca CORS w IE9 z ograniczonym dodatkowym kodowaniem.

https://github.com/jpillora/xdomain

Bernarda
źródło
-1

Uwaga - uwaga

nie używaj „ http://www.domain.xxx ”, „ http: // localhost / ” lub „IP >> 127.0.0.1” jako adresu URL w ajax. używaj tylko ścieżki (katalogu) i nazwy strony bez adresu.

stan fałszywy:

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

stan rzeczywisty:

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
źródło