如何从CodePen中的外部提供程序获取数据?

时间:2017-03-23 07:31:04

标签: javascript cors

我正在FreeCodeCamp处理JavaScript挑战。其中之一是创建一个检索和显示天气信息的网页。

首先,我尝试使用多个提供程序(例如OpenWeatherMap,WeatherUnderground),它们使用HTTP协议返回天气数据。由于mixed content错误,它无效。

接下来,我切换到提供商,该提供商通过HTTPS提供数据。我摆脱了混合内容问题,但得到了另一个问题:

  

XMLHttpRequest无法加载https://api.weatherbit.io/v1.0/current?lat=55.7767723&lon=37.6090795&units=S&key=XXXXXXXX。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许原点“https://s.codepen.io”访问。响应的HTTP状态代码为403。

我尝试根据this tutorial实现CORS:

function createCORSRequest(method, url) {
  var xhr = new XMLHttpRequest();
  if ("withCredentials" in xhr) {

    // Check if the XMLHttpRequest object has a "withCredentials" property.
    // "withCredentials" only exists on XMLHTTPRequest2 objects.
    xhr.open(method, url, true);

  } else if (typeof XDomainRequest != "undefined") {

    // Otherwise, check if XDomainRequest.
    // XDomainRequest only exists in IE, and is IE's way of making CORS requests.
    xhr = new XDomainRequest();
    xhr.open(method, url);

  } else {

    // Otherwise, CORS is not supported by the browser.
    xhr = null;

  }
  return xhr;
}

[...]

var url = "https://api.weatherbit.io/v1.0/current?lat=" + position.coords.latitude + "&lon=" + position.coords.longitude + "&units=S&key=XXXXXXXX";
var xhr = createCORSRequest('GET', url);
if (xhr) {
    xhr.onload = function() {
      var responseText = xhr.responseText;
      console.log("Response: " + responseText);
    };

    xhr.onerror = function() {
      console.log('There was an error!');
    };
    xhr.send();
}

当我致电xhr.send()时,我仍然收到错误。

我该如何解决?

注意:我正在寻找一个可以在CodePen中运行的解决方案。

更新1(23.03.2017 11:35 MSK):我尝试实施sideshowbarker的答案并修改了这样的代码:

function getCurrent(json){
     console.log("getCurrent called");
     console.log(json.data.temp);
     console.log(json.data.precip);
}

function updateWeather() {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function(position) {
      var url = "https://api.weatherbit.io/v1.0/current?callback=getCurrent&lat=" + position.coords.latitude + "&lon=" + position.coords.longitude + "&units=S&key=XXXXXXXXX";
      console.log("url: " + url);
      $.get(url, function(val){});
    });
  } else {
    console.log("Cannot obtain location data");
  };
}

updateWeather();

结果:

Screenshot with error messages

更新2(23.03.2017 13:29 MSK):这个有效。

 function getCurrent(json) {
   console.log("getCurrent called");
   console.log(JSON.stringify(json));
   // TODO: Update the UI here
 }

 function updateWeather() {
   if (navigator.geolocation) {
     navigator.geolocation.getCurrentPosition(function(position) {
       var url = "https://api.darksky.net/forecast/XXXXXXXXX/37.8267,-122.4233?callback=getCurrent";

       var script = document.createElement('script');
       script.src = url;

       document.getElementsByTagName('head')[0].appendChild(script);

     });
   }
 }

 updateWeather();

2 个答案:

答案 0 :(得分:1)

Weatherbit.io API不支持从XHR发出的跨源请求。

相反,API要求您使用带有JSONP回调的script元素发出请求:

<script>
    function getCurrent(json){
        console.log(json.data.temp)
        console.log(json.data.precip)
    }
</script>

<script
src="https://api.weatherbit.io/v1.0/current?callback=getCurrent&lat=NNN&lon=NNN&units=S&key=XX"></script>

当然,您可能希望让代码使用URL和params注入script元素。

这种使用JSONP回调注入script元素的方法是他们支持从Web应用程序使用API​​的唯一直接方法。

如果代码使用XHR向API发出请求,则代码无法运行;他们没有发送必要的Access-Control-Allow-Origin响应标头,因此,由于缺少该标头,您的浏览器不会让您的客户端JavaScript访问响应交叉源。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS解释了原因。

使用XHR处理其API的唯一方法是使用https://github.com/Rob--W/cors-anywhere/中的代码或类似代码设置CORS代理 - 或者如果您通过公共CORS代理发送请求,例如{{3 (你不想这样做,因为它会让该服务的所有者访问你的Weatherbit.io API密钥)。

代理的工作方式是,不使用weatherbit.io网址,而是使用代理网址https://cors-anywhere.herokuapp.com/https://api.weatherbit.io/v1.0/current…,代理将其发送到weatherbit.io,获取响应,然后添加{ {1}}响应标头返回到您的代码和浏览器看到的响应。

答案 1 :(得分:0)

我正在完成FCC中的天气应用程序并遇到了同样的问题。我能够使用以下行来使用它:

$.getJSON("https://api.weatherbit.io/v1.0/current?lat=##&lon=##&key=##", function(data){};

无论出于何种原因,只有“http://”才能使用它,我必须将其更改为“https://”才能使其正常工作。

不确定将来是否有助于任何人。