XMLHttpRequest асинхронный не работает, всегда возвращает статус 0 - PullRequest
11 голосов
/ 13 сентября 2011

Вот пример 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.

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

Ответы [ 5 ]

16 голосов
/ 13 сентября 2011

Вы можете использовать функцию внутри оператора if. Эта функция выполняется, когда состояние готовности изменяется на 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);

Ваш старый код выполнял асинхронный вызов и продолжал только с оператором оповещения. 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 = в порядке, 404 = не найден и т. Д.)

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

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

9 голосов
/ 13 сентября 2011

Статус Ноль происходит по двум причинам.

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

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

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

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

3 голосов
/ 13 сентября 2011

Это потому, что 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);
    }
  }
1 голос
/ 25 февраля 2014

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

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

Источник: Список рассылки Flask

0 голосов
/ 30 октября 2013

Я получил хороший ответ на эту распространенную проблему. Ответ следует:

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

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