我正在 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();
结果:
更新 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/