简体   繁体   English

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

[英]How to get data from an external provider in CodePen?

I'm doing the JavaScript challenges at FreeCodeCamp .我正在 FreeCodeCamp 进行JavaScript挑战。 One of them is to create a web page that retrieves and displays weather information.其中之一是创建一个 web 页面来检索和显示天气信息。

First, I tried to use several providers (eg OpenWeatherMap, WeatherUnderground ), which use the HTTP protocol to return weather data.首先,我尝试使用几个提供程序(例如 OpenWeatherMap、 WeatherUnderground ),它们使用 HTTP 协议返回天气数据。 It didn't work because of the mixed content error.由于混合内容错误,它不起作用。

Next, I switched to a provider, which delivers the data via HTTPS. I got rid of the mixed content problem, but got another one:接下来,我切换到一个提供商,它通过 HTTPS 传送数据。我摆脱了混合内容问题,但又遇到了另一个问题:

XMLHttpRequest cannot load https://api.weatherbit.io/v1.0/current?lat=55.7767723&lon=37.6090795&units=S&key=XXXXXXXX . XMLHttpRequest 无法加载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.请求的资源上不存在“Access-Control-Allow-Origin”header。 Origin ' https://s.codepen.io ' is therefore not allowed access.因此不允许访问来源“ https://s.codepen.io ”。 The response had HTTP status code 403.响应具有 HTTP 状态代码 403。

I tried to implement CORS according to 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();
}

When I call xhr.send() I still get the error.当我调用xhr.send()时,我仍然收到错误消息。

How can I fix it?我该如何解决?

Note: I'm looking for a solution that will run in CodePen .注意:我正在寻找将在CodePen中运行的解决方案。

Update 1 (23.03.2017 11:35 MSK): I tried to implement sideshowbarker's answer and modified the code like this:更新 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();

The result:结果:

带有错误消息的屏幕截图

Update 2 (23.03.2017 13:29 MSK): This one works.更新 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();

The Weatherbit.io API doesn't support cross-origin requests made from XHR. Weatherbit.io API 不支持从 XHR 发出的跨源请求。

Instead the API requires you make the requests using a script element with a JSONP callback:相反,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>

Of course you likely want to have your code inject that script element with the URL and params.当然,您可能希望您的代码使用 URL 和参数注入该script元素。

That's method of injecting the script element with a JSONP callback is the only direct method they support for using their API from a web app.这是使用 JSONP 回调注入script元素的方法,是他们支持从 web 应用程序使用其 API 的唯一直接方法。

There's no way your code will work if it instead makes the request to their API using XHR;如果您的代码使用 XHR 向他们的 API 发出请求,那么您的代码将无法工作; they don't send the necessary Access-Control-Allow-Origin response header, and so because that's missing, your browser won't let your client-side JavaScript access the response cross-origin.他们不发送必要的Access-Control-Allow-Origin响应 header,因此由于缺少响应,您的浏览器不会让您的客户端 JavaScript 访问跨源响应。

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

The only way you could use XHR to work with their API is if you set up a CORS proxy using code from https://github.com/Rob--W/cors-anywhere/ or something similar—or if you send your request through an public CORS proxy like https://github.com/Rob--W/cors-anywhere/ (which you don't want to do because that'd give the owner of that service access to your Weatherbit.io API key).你可以使用 XHR 来处理他们的 API 的唯一方法是,如果你使用https://github.com/Rob--W/cors-anywhere/或类似的代码设置一个 CORS 代理,或者如果你发送你的请求通过公共 CORS 代理,例如https://github.com/Rob--W/cors-anywhere/ (您不想这样做,因为这会让该服务的所有者访问您的 Weatherbit.io API 密钥).

The way the proxy works is that instead of using weatherbit.io URL, you use a proxy URL like https://cors-anywhere.herokuapp.com/https://api.weatherbit.io/v1.0/current… , and the proxy sends it on to weatherbit.io, gets the response back, then adds the Access-Control-Allow-Origin response header to the response it hands back to your code and that the browser sees.代理的工作方式是不使用 weatherbit.io URL,而是使用代理 URL,例如https://cors-anywhere.herokuapp.com/https://api.weatherbit.io/v1.0/current… ,然后代理将它发送到 weatherbit.io,获取响应,然后将Access-Control-Allow-Origin响应 header 添加到它返回给您的代码并且浏览器看到的响应中。

I was in the process of completing the Weather App in FCC and came across the same issue.我在 FCC 中完成天气应用程序的过程中遇到了同样的问题。 I was able to get it to work with the following line:我能够让它与以下行一起工作:

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

For whatever reason, it wouldn't work with just "http://", I had to change it to "https://" in order for it to work.不管出于什么原因,它不能仅使用“http://”,我必须将其更改为“https://”才能使其正常工作。

Not sure if that helps anyone in the future.不确定这是否对将来的任何人有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM