I'm making a weather app with React.js and I want to make a CORS request for fetching data from weather underground website. What I want is getting a city name, use autocomplete API for finding the city and fetch data for that city.
The problem is, everytime I give a city name (for example: tehran), the xhr.onerror
event handler runs and I get this error:
XMLHttpRequest cannot load http://autocomplete.wunderground.com/aq?query=tehran. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
This is my code for fetching data:
var axios = require('axios');
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
xhr.open(method, url, true);
}
else if (typeof XDomainRequest != "undefined") {
xhr = new XDomainRequest();
xhr.open(method, url);
}
else {
xhr = null;
}
return xhr;
}
function makeCorsRequest(url) {
var autoCompleteText;
var xhr = createCORSRequest('GET', url);
if (!xhr) {
alert('CORS not supported');
return;
}
xhr.onload = function() {
var text = xhr.responseText;
autoCompleteText = text;
}
xhr.onerror = function() {
alert('Woops, there was an error making the request.');
}
xhr.send();
return autoCompleteText;
}
const WEATHER_UNDERGROUND_AUTOCOMPLETE = 'http://autocomplete.wunderground.com/aq?query=';
const WEATHER_UNDERGROUND_URL = 'http://api.wunderground.com/api/eda52d06d32d71e9/conditions/q/';
module.exports = {
getTemp: function(city) {
var encodedCity = encodeURIComponent(city);
var requestAutoComplete = `${WEATHER_UNDERGROUND_AUTOCOMPLETE}${encodedCity}`;
var autoCompleteText = makeCorsRequest(requestAutoComplete);
var foundCity = autoCompleteText.RESULTS[0].name.split(', ');
var requestUrl = `${WEATHER_UNDERGROUND_URL}${foundCity[1]}/${foundcity[0]}.json`;
return axios.get(requestUrl).then(function(res) {
return res.data.current_observation.temp_c;
}, function(err) {
throw new Error(res.data.error);
});
}
}
Screenshot of the app: localhost:3000/weather page
Here is a simple react component which calls the api with query params and get 's the desired result.
import React, { Component } from 'react'
import axios from 'axios';
export default class App extends Component {
componentDidMount() {
axios.get('http://autocomplete.wunderground.com/aq?query=tehran')
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
})
}
render () {
return (
<div>React simple starter</div>
)
}
}
Because http://autocomplete.wunderground.com/aq?query=tehran
doesn't send the Access-Control-Allow-Origin
response header, you must change your frontend code to instead make the request through proxy. Do that by changing the WEATHER_UNDERGROUND_AUTOCOMPLETE
value:
const WEATHER_UNDERGROUND_AUTOCOMPLETE =
'https://cors-anywhere.herokuapp.com/http://autocomplete.wunderground.com/aq?query=';
The https://cors-anywhere.herokuapp.com/http://autocomplete.wunderground.com/…
URL will cause the request to go to https://cors-anywhere.herokuapp.com
, a public CORS proxy which sends the request on to the http://autocomplete.wunderground.com…
URL you want.
That proxy gets the response, takes it and adds the Access-Control-Allow-Origin
response header to it, and then finally passes that back to your requesting frontend code as the response.
So in the end because the browser sees a response with the Access-Control-Allow-Origin
response header, the browser allows your frontend JavaScript code to access the response.
Or use the code from https://github.com/Rob--W/cors-anywhere/ or such to set up your own proxy.
You need a proxy in this case because http://autocomplete.wunderground.com/…
itself doesn't send the Access-Control-Allow-Origin
response header—and in that case your browser will not allow your frontend JavaScript code to access a response from that server cross-origin.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS has more details.
Incidentally, you can use curl
or some other tool to verify that server isn't sending the header:
$ curl -i -H 'Origin: http://localhost:3000' \
'http://autocomplete.wunderground.com/aq?query=tehran'
HTTP/1.1 200 OK
Content-type: application/json; charset=utf-8
Content-Length: 2232
Connection: keep-alive
{ "RESULTS": [
{
"name": "Tehran Dasht, Iran",
…
Notice there's no Access-Control-Allow-Origin
in the response headers there.
Are you bound to using axios? if not I would highly recommend Mozilla's Fetch. To make a cors api call with fetch, do this:
var myInit = {
method: 'GET',
mode: 'cors',
credentials: 'include'
};
fetch(YOUR_URL, myInit)
.then(function(response) {
return response.json();
})
.then(function(json) {
console.log(json)
});
You can learn more here: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
If you are facing issues making CORS
request, then use this simple chrome extension (Allow control Allow origin) .
This will let you make CORS
request without adding any extra parameter in headers/config
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.