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?


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


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

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


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/


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ź.


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



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


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.




-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);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.