IE, XDomainRequest не всегда работает - PullRequest
11 голосов
/ 09 ноября 2011

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

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

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

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

Большое спасибо, коронин

Ответы [ 2 ]

19 голосов
/ 20 декабря 2014

В объекте 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, выходит из области видимости. Если пользователю не повезло, сборщик мусора Javascript в IE запустится до того, как send () выполнит асинхронно, и запрос будет прерван. Даже если объект 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 распространяются все его обычные ограничения и ограничения . Это не ошибки как таковые, а по сравнению с предупреждениями (iframe kludges, Flash crossdomain.xml) они не , плохие.

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

11 голосов
/ 28 марта 2012

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

  1. Используйте этот код: https://github.com/jaubourg/ajaxHooks/blob/master/src/ajax/xdr.js

ОБНОВЛЕНИЕ: ссылка не работает, найдите исправление jaubourgs здесь: https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

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

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

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

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

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

...