IE, XDomainRequest не всегда работают

Я пытаюсь сделать кросс-домен в IE.

Я использовал XDomainRequest и имплантировал ведение журнала для всех событий (onerror, onload, onprogress и ontimeout) для отслеживания прогресса.

Он работает некогда, но не всегда (один компьютер, IE9, тот же сайт, тот же запрос, 1 из 3 или 4, другой компьютер, IE8, возможно, 1 из 2 работ). Я не получил никакой полезной информации из журнала, потому что ничего не было вызвано.

Я очень смущен. Любой инструмент отладки для IE? Почему некоторое время XDomainRequest просто не работает?

Большое спасибо coronin

Ответ 1

В объекте XDomainRequest есть как минимум две существенные ошибки: одна, которая влияет на IE8, а другая - на IE9.

Проблема 1 - Сбор мусора

В Internet Explorer 8 объект XDomainRequest некорректно подчиняется сборке мусора после того, как send() был вызван, но еще не завершен. Симптомами этой ошибки являются сетевая трассировка инструментов разработчика, показывающая "Отменена" для запросов и ни один из обработчиков ошибок, тайм-аутов или обработчиков событий.

Типичный код AJAX выглядит примерно так:

function sendCrossDomainAjax(url, successCallback, errorCallback) {
  var xdr = new XDomainRequest();
  xdr.open("get", url);
  xdr.onload = function() { successCallback(); }
  xdr.onerror = function() { errorCallback(); }
  xdr.send();
}

В этом примере переменная, содержащая XDomainRequest, выходит за рамки. Если пользователю повезло, сборщик мусора IE Javascript будет запущен перед отправкой() асинхронно завершен, и запрос будет прерван. Несмотря на то, что объект XDomainRequest может быть захвачен в обработчики событий OnLoad и OnError, IE увидит, что весь граф объекта не имеет ссылок на него и будет собирать мусор. IE должен "привязывать" объект до завершения.

Вы заметите немало других обсуждений в Интернете, в которых упоминается, что размещение setTimeout вокруг xdr.send(); вызов каким-то образом "решает" загадочные неудачи XDomainRequest. Это колчан и совершенно неправильный. Все, что происходит, заключается в том, что объект XDomainRequest "закрепляется" в закрытии setTimeout и не подвергается сбору мусора так же быстро. Это не решает проблему.

Чтобы правильно обойти эту проблему, убедитесь, что XDomainRequest хранится в глобальной переменной до тех пор, пока запрос не завершится. Например:

var pendingXDR = [];

function removeXDR(xdr) {
  // indexOf isn't always supported, you can also use jQuery.inArray()
  var index = pendingXDR.indexOf(xdr);
  if (index >= 0) {
    pendingXDR.splice(index, 1);
  }
}

function sendCrossDomainAjax(url, successCallback, errorCallback) {
  var xdr = new XDomainRequest();
  xdr.open("get", url);

  xdr.onload = function() {
    removeXDR(xdr);
    successCallback();
  }

  xdr.onerror = function() {
    removeXDR(xdr);
    errorCallback();
  }

  xdr.send();
  pendingXDR.push(xdr);
}

Проблема 2 - Отсутствует OnProgress EventHandler

Эта вторая проблема уже известна. Internet Explorer 9 представил регрессию в объекте XDomainRequest, где отсутствующий (нулевой) обработчик события OnProgress заставит запрос прерывать, когда он пытается сообщить информацию о ходе.

Для быстрых запросов IE9 никогда не пытается вызвать обработчик события OnProgress, и запрос успешно завершен. Некоторые условия, например, когда IE задерживает запрос из-за слишком большого количества открытых подключений, задержек в сети, медленных ответов сервера или больших запросов или запросов, приведет к тому, что IE9 начнет сообщать информацию о ходе.

IE9 пытается вызвать обработчик события, не проверив его, и объект XDomainRequest падает и сам разрушает себя.

Чтобы решить эту проблему, всегда убедитесь, что обработчик событий подключен к OnProgress. Учитывая ошибку, это не плохая идея, чтобы защищать обработчики событий ко всем событиям объекта.

var xdr = new XDomainRequest();
xdr.open("get", url);
xdr.onprogress = function() { };
// regsister other event handlers

Другие проблемы

Мне кажется, что XDomainRequest может выйти из строя, если обработчики событий зарегистрированы до вызова функции .open(). Опять же, оборонительно, неплохо было бы зарегистрировать их между вызовами .open() и .send(). Я лично не проверял, действительно ли это ошибка.

Если вы столкнулись с ошибкой "Отказано в доступе", это связано с тем, что XDomainRequest не разрешает несогласованные схемы URI между целевой и главной страницей. Другими словами, попробуйте не вызывать ресурс HTTP с HTTPS-страницы.

Остерегайтесь большинства библиотек XDomainRequest в Интернете. Я смотрел на большинство популярных, таких как различные jQuery AJAX транспортные плагины (в том числе те, которые связаны в другом ответе здесь).

И, конечно же, XDomainRequest подчиняется всем нормальным ограничениям и ограничениям. Это не ошибки, а по сравнению с alernatives (iframe kludges, Flash crossdomain.xml transports) они не , которые плохие.

Я разместил новый транспорт jQuery AJAX XDomainRequest под лицензией общественного домена здесь: https://github.com/ebickle/snippets/tree/master/javascript/xdomainrequest

Ответ 2

Был тот же самый вопрос. Краткое решение:

UPDATE: ссылка сломана, найдите jaubourgs здесь: https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

  1. Добавьте xdr.onprogress = function() {}; в этот файл xdr.js

Подробности можно найти в обсуждении темы jQuery здесь

http://bugs.jquery.com/ticket/8283

в котором в последнем ответе было указано, что xdr.onprogress fix, возникший из этого обсуждения ошибок, который был метко назван

"IE9 RTM - выпущенные запросы XDomainRequest могут прерываться, если все обработчики событий не указаны" http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/30ef3add-767c-4436-b8a9-f1ca19b4812e