XMLHttpRequest асинхронный не работает, всегда возвращает статус 0

Здесь образец XMLHttpRequest, который я вымотал из w3schools

<html>
<head>
<script type="text/javascript">
function loadXMLDoc()
{
  var T="nothing";

  xmlhttp=new XMLHttpRequest();
  xmlhttp.overrideMimeType('text/plain');  // don't sc
  xmlhttp.onreadystatechange=function()
  {
    alert ("rdystate: " + xmlhttp.readyState);
    alert ("status: "   + xmlhttp.status);
    alert ("Text: "     + xmlhttp.statusText);
    if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
      T = xmlhttp.responseText;
    }
  }
xmlhttp.open("GET","SBL_PROBES.htm",true);
xmlhttp.send(null);
//T = xmlhttp.responseText;
alert(T);
}
</script>
</head>
<body>

<h2>Using the XMLHttpRequest object</h2>
<div id="myDiv"></div>
<button type="button" onclick="loadXMLDoc()">CHange Content</button>

</body>
</html>

XMLHttpRequest всегда возвращает нулевой статус.

Ничего не отображается в консоли ошибок Firefox.

Если я изменил запрос на синхронный, изменив строку

xmlhttp.open("GET","SBL_PROBES.htm",true);

к

xmlhttp.open("GET","SBL_PROBES.htm",false);

и не комментировать строку

//T = xmlhttp.responseText;

Возвращается текст запрашиваемого файла.

HTM и файл находятся в одном каталоге. Если вы попробуете это, вам понадобится файл SBL_PROBES.htm, также он не имеет значения.

Я использую Firefox 3.6.22.

Может ли это быть проблемой перекрестного домена? Если да, то почему он работает как синхронный запрос?

Ответ 1

Вы можете использовать функцию внутри оператора if. Эта функция выполняется, когда readystate изменяется на 4.

var handleResponse = function (status, response) {
   alert(response)
}
var handleStateChange = function () {
   switch (xmlhttp.readyState) {
      case 0 : // UNINITIALIZED
      case 1 : // LOADING
      case 2 : // LOADED
      case 3 : // INTERACTIVE
      break;
      case 4 : // COMPLETED
      handleResponse(xmlhttp.status, xmlhttp.responseText);
      break;
      default: alert("error");
   }
}
var xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=handleStateChange;
xmlhttp.open("GET","SBL_PROBES.htm",true);
xmlhttp.send(null);

Ваш старый код выполнил асинхронный вызов и продолжался только с помощью Statement Statement. В это время T был пуст.

Хорошо, я немного объясню, как все это работает:

Сначала мы определяем две функции обратного вызова, которые мы вызываем позже в запросе, с именем handleResponse и handleStateChange.

Затем мы создаем объект, представляющий XMLHttpRequest

var xmlhttp=new XMLHttpRequest();

Это приводит к объекту следующим образом (простое):

XMLHttpRequest { status=0, readyState=0, multipart=false, onreadystatechange=handleEvent()}

При вызове функции open (...) вы задаете параметры для запроса:

xmlhttp.open("GET","SBL_PROBES.htm",true);

Это означает, что асинхронный запрос GET для получения страницы SBL_PROBES.htm Затем вызывается функция send (...), которая запускает сам запрос.

Мы зарегистрировали функцию обратного вызова для onreadystatechange, как вы можете себе представить, это на самом деле eventHandler. Каждый раз, когда состояние изменяется, эта функция вызывается. (Это то же самое, что если вы регистрируете функцию обратного вызова для события onKeyUp в форме, этот обратный вызов запускается каждый раз, когда ваш ключ увеличивается:))

Единственный случай, который представляет интерес для вашей проблемы, - это состояние 4. Поэтому функция обратного вызова handleRequest вызывается только в состоянии 4. В это время у вашего запроса есть результат, а также статус. (Статус означает, что ваш веб-сервер возвратил код состояния 200 = ok, 404 = не найден и т.д.)

Это не вся магия, которая стоит за материалом ajax, но должна дать вам упрощенный обзор, что на самом деле происходит за кулисами. Важно, чтобы вы протестировали это на веб-сервере, не используйте файл://для тестирования.

Если вам нужна более подробная информация, просто дайте мне знать.

Ответ 2

Состояние Zero происходит по двум причинам.

  • Вы удаляете протокол файлов.
  • Что-то отправляет страницу назад, когда активен запрос Ajax.

Я считаю, что вы видите здесь # 2. Так что вам нужно отменить нажатие кнопки.

<button type="button" onclick="loadXMLDoc(); return false;">CHange Content</button>

В вашем коде выше предупреждение (T) всегда будет говорить ничего, когда запрос является асинхронным.

Ответ 3

Это потому, что async возвращается до возврата запроса. Синхронные запросы возвращаются после возврата запроса.

Попробуйте манипулировать своей логикой здесь.

xmlhttp.onreadystatechange=function()
  {
    alert ("rdystate: " + xmlhttp.readyState);
    alert ("status: "   + xmlhttp.status);
    alert ("Text: "     + xmlhttp.statusText);
    if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
      T = xmlhttp.responseText;
      alert(T);
    }
  }

Ответ 4

Я столкнулся с проблемой не получения результата при использовании асинхронного оператора XMLHttpRequest open. Поскольку этот вопрос является первым, который я нашел при использовании Google, вот как я его решил:

Если вы используете кнопку, находящуюся внутри формы, убедитесь, что она настроена на type = "submit" и onclick = "return myFunction()". И в myFunction() убедитесь, что вы вернули false, не true! Вернув true из функции, вы перезагрузите страницу, и объект XML исчезнет. Если вы вернете false, запрос XML получит время, необходимое для завершения, и будет запущена функция onreadystatechange.

Источник: Список рассылок флагов

Ответ 5

Теперь я получил хороший ответ на эту общую проблему. Ответ:

Это очень распространенная проблема при разработке для Интернета. Там есть два пути.

  • Во-первых, использовать JSONP, который поддерживает наш API, когда вы добавляете параметр запроса ( "? callback = foo" ). Это должно заставить вас работать и работать сразу и отлично подходит для разработки, но не безопасно для производства, так как пользователи получают доступ к вашему ключу API.
  • Второе (это то, что мы используем в Forecast, и является лучшим методом для производства) заключается в настройке прокси-сервера в вашем собственном домене, который может делать запросы к прогнозу от имени пользователя. Это оборачивает политику браузера с одинаковым исходным кодом, предотвращает доступ пользователей к вашему ключу API (который может храниться на стороне сервера), а также позволяет использовать кэширование запросов, если это необходимо. (Наш любимый веб-сервер, NGINX, поддерживает это из коробки и действительно легко настраивается. Если вам нужны некоторые примеры конфигураций, дайте нам знать!)