IE9 jQuery AJAX с CORS возвращает «Доступ запрещен»

123

Следующее работает во всех браузерах, кроме IE (я тестирую в 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'
            }
        );

У меня есть еще одна функция, которая использует dataType: 'jsonp' , но мне не нужны данные, возвращаемые этим вызовом AJAX. Мое последнее средство - вернуть какую-нибудь треп, обернутую в JSONP, чтобы заставить его работать.

Есть идеи, почему IE облажается с запросом CORS, который не возвращает данных?

Garrett
источник
Поскольку ни один из предложенных ответов не помог мне (мне также пришлось передать файлы cookie в запрос CORS, что недопустимо при использовании XDomainRequest), вот обходной путь : blog.gauffin.org/2014/04/… , Прокси на помощь! : p
wimvds

Ответы:

150

Это известная ошибка jQuery. Команда jQuery «не планирует поддерживать это в ядре и лучше подходит как плагин». (См. Этот комментарий ). IE не использует XMLHttpRequest , а использует альтернативный объект с именем XDomainRequest .

Там является плагин для поддержки этого в JQuery, который можно найти здесь : https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

РЕДАКТИРОВАТЬ Функция $.ajaxTransportрегистрирует фабрику транспортеров. Переносчика используется внутри по $.ajaxдля выполнения запросов. Поэтому я предполагаю, что вы сможете звонить $.ajaxкак обычно. Информацию о транспортерах и расширении $.ajaxможно найти здесь .

Также здесь можно найти, возможно, лучшую версию этого плагина .

Два других примечания:

  1. Объект XDomainRequest появился в IE8 и не будет работать в версиях ниже.
  2. В IE10 CORS будет поддерживаться с помощью обычного XMLHttpRequest .

Изменить 2: проблема http в https

Запросы должны быть нацелены на ту же схему, что и страница хостинга.

Это ограничение означает, что если ваша страница AJAX находится по адресу http://example.com , ваш целевой URL также должен начинаться с HTTP. Точно так же, если ваша страница AJAX находится по адресу https://example.com , тогда ваш целевой URL также должен начинаться с HTTPS.

Источник: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

dennisg
источник
12
«Лучшая версия» плагина является врожденной; Я просто включил его на свою страницу, и он автоматически исправил мои вызовы $ .ajax :) При условии, конечно, что у вас есть все необходимые заголовки .
Kato
5
Чтобы добавить к ответу dennisg, xdr.js имеет ошибку - обратный вызов ajaxTransport не будет вызываться как есть. Мне пришлось изменить его в соответствии с stackoverflow.com/questions/12481560/… (добавлен «+ *» в качестве первого аргумента вызова ajaxTransport).
Владимир Отрышко 06
4
jQuery.XDomainRequest.js гарантирует, что текущая страница и удаленная страница являются как http, так и https. Означает ли это, что вы не можете вызвать https API со страницы http?
Аарон
2
Стоит отметить, что код, который был связан с репозиторием github moonscripts, является старой версией, которая не работает. Обязательно загрузите
Клинтм
3
@Aaron, добавив к комментарию @HariKaramSingh: изменение протоколов ( httpна https), доменов ( google.comна bing.com), субдоменов ( mail.google.comна maps.google.com) или протоколов ( google.com:80- порт по умолчанию на google.com:8080) вызовет «междоменный» запрос. По сути, все, что находится перед первым /в вашем URL, должно быть идентичным.
allicarn
62

Основываясь на принятом ответе @dennisg, я успешно выполнил это, используя jQuery.XDomainRequest.js от MoonScript.

Следующий код работал правильно в Chrome, Firefox и IE10, но не работал в IE9. Я просто включил скрипт, и теперь он автоматически работает в IE9. (И, наверное, 8, но я не тестировал.)

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
источник
3
Плагин jQuery.XDomainRequest.js был именно тем, что мне было нужно! Мне не удалось заставить плагин iexhr.js работать с запросами за базовой аутентификацией HTTP, но XDomainRequest работал как шарм!
Джеймс Форд
Это сработало для меня. Мне не нужен Site.config (). ApiRoot + (который, как я предполагаю, предназначен для твиттера ....) Но он отлично работает, спасибо за это.
Николас Деккер
@NicholasDecker Site.config (). ApiRoot - это просто конкретный код реализации для получения корневого URL-адреса API, ничего универсального или необычного. Рад, что помог!
JackMorrissey
Я надеялся, что это сработает для меня, но я пытаюсь выполнить POST. интересно, это проблема для меня.
Джек Маркетти
1
@cracker У вас проблемы только с POST? Дважды проверьте, что скрипт загружается после jQuery и ваш вызов соответствует документации MoonScript.
JackMorrissey
16

Полные инструкции о том, как это сделать с помощью плагина "jQuery-ajaxTransport-XDomainRequest", можно найти здесь: https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest#instructions

Этот плагин активно поддерживается и обрабатывает HTML, JSON и XML. Файл также размещен на CDNJS, поэтому вы можете напрямую перетащить скрипт на свою страницу без дополнительной настройки: http://cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.1/jquery.xdomainrequest .min.js

MoonScript
источник
1
Это отлично сработало - исправьте. Невероятно, что эта проблема существует в jQuery, но ... Спасибо!
Cymen
3

Проблема в том, что IE9 и ниже не поддерживают CORS. XDomainRequest поддерживает только GET / POST и text/plainтип содержимого, как описано здесь: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

Поэтому, если вы хотите использовать все HTTP-глаголы и / или json и т. Д., Вам нужно использовать другое решение. Я написал прокси, который плавно перейдет на прокси, если используется IE9 или меньше. Вам вообще не нужно менять свой код, если вы используете ASP.NET.

Решение состоит из двух частей. Первый - это сценарий jquery, который подключается к обработке jQuery ajax. Он автоматически вызовет веб-сервер, если выполняется запрос между доменами и браузер 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;
    }
});

На своем веб-сервере вы должны получить запрос, получить значение из HTTP-заголовка X-CorsProxy-Url, выполнить HTTP-запрос и, наконец, вернуть результат.

Сообщение в моем блоге: http://blog.gauffin.org/2014/04/how-to-use-cors-requests-in-internet-explorer-9-and-below/

jgauffin
источник
1

Я просто делал все запросы JSONP, потому что это было единственное решение для всех наших поддерживаемых браузеров (IE7 + и постоянных клиентов). Имейте в виду, что ваш ответ технически работает для IE9, поэтому у вас есть правильный ответ.

Garrett
источник
2
Просто примечание для всех, у кого есть эта проблема - в этом случае, если у вас есть требование <= IE7, и у вас нет контроля над сервером (например, вы не можете заставить его поддерживать теги сценария GET + с JSONP), ваш Лучшим вариантом является облегченный сервер промежуточного программного обеспечения, который переводит вызов JSONP в POST и передает ответ от сервера черного ящика обратно пользователю.
mikermcneil
1

Основываясь на решении MoonScript, вы можете попробовать следующее:

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

Преимущество заключается в том, что, поскольку это решение более низкого уровня, оно будет включать CORS (насколько это возможно) в IE 8/9 с другими фреймворками, а не только с jQuery. Я успешно использовал его с AngularJS, а также с jQuery 1.x и 2.x.

Янни
источник
0

Чтобы решить эту проблему, также проверьте, есть ли у вас какие-либо включенные .js в ваш файл ajax с именем: Я получил ошибку отказа в доступе при включении shadowbox.js в мой ajax.php

hacklover
источник
0

Я тестировал веб-службу CORS на своей машине разработчика и получал сообщение об ошибке «Доступ запрещен» только в IE. Firefox и Chrome работали нормально. Оказывается, это было вызвано тем, что я использовал localhost в вызове ajax! Итак, мой URL-адрес браузера был примерно таким:

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

и мой вызов ajax внутри test.html был примерно таким:

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

Все заработало, когда я изменил вызов ajax, чтобы использовать IP-адрес моего компьютера вместо localhost.

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

Вкладка «Сеть» окна инструментов разработчика IE также показывает запрос CORS Preflight OPTIONS, за которым следует XMLHttpRequest GET, что я и ожидал увидеть.

jwill212
источник
0

Обновление от начала 2015 года. XDomain - широко используемая библиотека для поддержки CORS в IE9 с ограниченным дополнительным кодированием.

https://github.com/jpillora/xdomain

Бернард
источник
-1

Примечание - Примечание

не используйте « http://www.domain.xxx », « http: // localhost / » или «IP >> 127.0.0.1» для URL-адреса в ajax. используйте только путь (каталог) и имя страницы без адреса.

ложное состояние:

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

истинное состояние:

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);
Али Багери
источник