首页 > 解决方案 > 当内容显然正确时,如何修复返回代码 0 的 XMLHttpRequest.open()?

问题描述

我正在尝试使用开发人员自动生成的链接调用 API。我正在使用基于https://javascript.info/xmlhttprequest教程的 XMLHttpRequest.open() 方法。但是,当我尝试拨打电话时,我能够达到的唯一状态是“0”,我认为这意味着我的结束(?)。

我尝试了到其他 API 的不同链接,包括那些除了普通链接之外不需要任何东西的链接,并且得到了相同的响应,这意味着它不一定与我想要的 API 和其他解决方案有关(例如$.JSON().done()) 也不合作。

我最小的代码:

<button onclick="getEndDate()">Click Me</button>

<script>
  function getEndDate() {
  alert("in function");
  // create request
  var request = new XMLHttpRequest()
  alert("request made");
  // request data from API (API link automatically generated)
request.open('GET', 'https://holidayapi.com/v1/holidays?key=validkey&country=US&year=2018&pretty', true)
  alert("request opened"+ request.status);
  // send request (?)
  request.send()
  alert("request sent");
request.onload = function() {
  alert("request loaded");
  var data = JSON.parse(this.response)
  // If we receive a valid code
  if (request.status >= 200 && request.status < 400) {
    data.forEach(holiday => {
      alert(holiday.name, holiday.date);
    })
  } else {
    alert('error');
  }
  }
}
</script>

我希望至少能够运行所有警报,但是我只能进入“已发送请求”,这意味着加载请求结果时存在问题。如前所述,在状态中,我期望的是 200 而不是 0。

我是否以完全错误的方式接近这个?如果是这样,我应该以什么方式尝试调用 API?

标签: javascriptjsonapi

解决方案


XMLHttpRequest 的send()方法以某种同步的方式运行。它的部分行为可能是异步的,也可能不是异步的(取决于.open()'sasync 标志),但它的一部分绝对是同步的。

设置事件处理程序(onloadonreadystatechange)是同步完成的。这就是 Internet Explorer 实现它的方式,并且自从 Microsoft 发明了 XMLHttpRequest 以来,规范要求它实现它。

具体来说,规范的第 5 步.send()要求它:

  1. 如果在关联的 XMLHttpRequestUpload 对象上注册了一个或多个事件侦听器,则设置上传侦听器标志。

所以设置事件监听器是在.send()函数返回之前完成的,而不是在收到来自网络的响应时。

所以在你的代码中你有:

request.send(); // send will now check if it has .onload registered and
                // set up appropriate event listeners.

request.onload = function() { /* ... */ } // too late, this is ignored

您需要在调用之前通过.onload.onreadystatechange或通过设置任何事件侦听器。.addEventListener('load', ...).send()

请注意,在XMLHttpRequest 使用的所有官方示例(whatwg 规范、MDN、MSDN 等)中,事件处理程序总是在之前设置,.open()所以我建议你做同样的事情,即使技术上规范允许你在之后.open()但之前这样做.send()

request.onload = function() { /* ... */ }
request.open('GET', url, true);
request.send();

过去有(我不知道目前是否有)一些浏览器版本允许您在之后设置事件处理程序,.send()因为它们使用标准 EventEmitters 而不是遵循规范。但是这些实现在技术上并不符合标准,即使感觉是正确的。


推荐阅读