javascript - 如何在 CodePen 中从外部提供者获取数据?

标签 javascript cors

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

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

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

XMLHttpRequest cannot load https://api.weatherbit.io/v1.0/current?lat=55.7767723&lon=37.6090795&units=S&key=XXXXXXXX. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://s.codepen.io' is therefore not allowed access. The response had HTTP status code 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(2017年3月23日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(2017 年 3 月 23 日 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();

最佳答案

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>

当然,您可能希望在代码中注入(inject)带有 URL 和参数的 script 元素。

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

如果您的代码使用 XHR 向他们的 API 发出请求,那么您的代码将无法工作;他们不会发送必要的 Access-Control-Allow-Origin 响应 header ,因此由于缺少该 header ,您的浏览器不会让您的客户端 JavaScript 访问跨源响应。

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

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

代理的工作方式是,您不使用weatherbit.io URL,而是使用像https://cors-anywhere.herokuapp.com/https://api.weatherbit.io/v1这样的代理URL .0/current…,代理将其发送到weatherbit.io,获取响应,然后将 Access-Control-Allow-Origin 响应 header 添加到它提供的响应中返回到浏览器看到的代码。

关于javascript - 如何在 CodePen 中从外部提供者获取数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42969742/

相关文章:

java - jetty 跨源过滤器

javascript - rails 和 CORS : why am I only seeing the OPTIONS request?

javascript - Three.js 对象 'shimmering' 远距离

javascript - 我应该为每个集合使用一个发布还是多个?

Azure 存储 Blob CORS 错误

javascript - Chrome CORB 阻止 APIGateway lambda 请求

javascript - 我的 JavaScript while 循环在第一个提示后停止

javascript - 在 Chrome PWA 中更改屏幕方向

javascript - 如何使用on click Angular函数让页面跳转到div?

amazon-web-services - Three.js AWS S3 CORS