【问题标题】:How to make CORS Request如何提出 CORS 请求
【发布时间】:2017-11-04 23:46:43
【问题描述】:

我正在使用 React.js 制作一个天气应用程序,并且我想发出一个 CORS 请求以从天气地下网站获取数据。 我想要的是获得一个城市名称,使用自动完成 API 来查找城市并获取该城市的数据。

问题是,每次我给出一个城市名称(例如:德黑兰),xhr.onerror 事件处理程序都会运行并且我得到这个错误:

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.

这是我获取数据的代码:

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);
        });
    }
}

应用截图: localhost:3000/weather page

【问题讨论】:

  • 你能试试 axios.get(requestAutoComplete) .then(function(response) { console.log(response); } .catch(function(error) { console.log(error); } );
  • 我在发布这个问题之前已经这样做了,但没有成功。
  • 你想分享屏幕吗?这样我可以更好地检查这个
  • 您请求资源的服务器没有设置必要的Access-Control-标头,除非有人修改后端,否则无法解决它,Access-Control-Allow-Origin只是其中之一跨域资源共享的标头
  • @user3408151 之所以有效,是因为您直接在地址栏中输入了地址,但这里 OP 使用的是 ajax,这是另一回事

标签: javascript ajax reactjs cors


【解决方案1】:

由于http://autocomplete.wunderground.com/aq?query=tehran 不发送Access-Control-Allow-Origin 响应标头,因此您必须更改前端代码以改为通过代理发出请求。通过更改 WEATHER_UNDERGROUND_AUTOCOMPLETE 值来做到这一点:

const WEATHER_UNDERGROUND_AUTOCOMPLETE =
  'https://cors-anywhere.herokuapp.com/http://autocomplete.wunderground.com/aq?query=';

https://cors-anywhere.herokuapp.com/http://autocomplete.wunderground.com/… URL 将导致请求转到 https://cors-anywhere.herokuapp.com,这是一个公共 CORS 代理,它将请求发送到您想要的 http://autocomplete.wunderground.com… URL。

该代理获取响应,接受它并向其添加Access-Control-Allow-Origin 响应标头,然后最终将其作为响应传递回您的请求前端代码。

所以最终因为浏览器看到带有Access-Control-Allow-Origin 响应标头的响应,浏览器允许您的前端 JavaScript 代码访问响应。

或者使用https://github.com/Rob--W/cors-anywhere/的代码或者类似的代码来设置你自己的代理。

在这种情况下,您需要一个代理,因为http://autocomplete.wunderground.com/… 本身不会发送Access-Control-Allow-Origin 响应标头——在这种情况下,您的浏览器将不允许您的前端 JavaScript 代码跨域访问来自该服务器的响应。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS 有更多详细信息。


顺便说一句,您可以使用curl 或其他工具来验证服务器没有发送标头:

$ 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",
        …

请注意,那里的响应标头中没有 Access-Control-Allow-Origin

【讨论】:

    【解决方案2】:

    这是一个简单的 react 组件,它使用查询参数调用 api 并获得所需的结果。

    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>
            )
        }
    }
    

    【讨论】:

      【解决方案3】:

      你一定要使用 axios 吗?如果不是,我强烈推荐 Mozilla 的 Fetch。要使用 fetch 进行 cors api 调用,请执行以下操作:

      var myInit = { 
          method: 'GET',
          mode: 'cors',
          credentials: 'include'
      };
      
      fetch(YOUR_URL, myInit)
      .then(function(response) {
          return response.json();
      })
      .then(function(json) {
          console.log(json)
      });
      

      您可以在这里了解更多信息:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

      【讨论】:

        【解决方案4】:

        如果您在发出CORS 请求时遇到问题,请使用这个简单的chrome extension (允许控制允许来源)

        这将使您无需在headers/config 中添加任何额外参数即可发出CORS 请求。

        【讨论】:

          猜你喜欢
          • 2015-09-13
          • 2020-05-24
          • 2017-03-02
          • 1970-01-01
          • 2017-05-15
          • 2015-03-02
          • 2018-02-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多