【问题标题】:ReactJS CORS header ‘Access-Control-Allow-Origin’ missing缺少 ReactJS CORS 标头“Access-Control-Allow-Origin”
【发布时间】:2021-09-15 04:45:40
【问题描述】:

我正在使用第 3 方 API https://www.metaweather.com 并在我的 package.json 中添加了
"proxy": "https://www.metaweather.com",

我的app.js如下:

import { createContext, useState } from "react";
import LocationSearch from "./components/locationSearch";
import MainWeather from "./components/mainWeather";
import ExtraWeather from "./components/ExtraWeather";

export const DisplayContext = createContext({
  display: false,
  setDisplay: () => {},
});

function App() {
  const [woeid, setWoeid] = useState(null);
  const [display, setDisplay] = useState(false);

  return (
    <DisplayContext.Provider value={{ display, setDisplay }}>
      <LocationSearch setWoeid={setWoeid} />
      <MainWeather woeid={woeid} />
      <ExtraWeather />
    </DisplayContext.Provider>
  );
}

export default App;

我的LocationSearch.jsx:

import React, { useContext, useState } from "react";
import axios from "axios";
import { DisplayContext } from "../App";

const LocationSearch = ({ setWoeid }) => {
  const [data, setData] = useState({
    location: "",
  });
  const { setDisplay } = useContext(DisplayContext);

  function submit(e) {
    e.preventDefault();
    axios
      .get(
        // "https://cors-anywhere.herokuapp.com/https://www.metaweather.com/api/location/search/?query=" +
          "/api/location/search/?query=" +
          data.location,
        {
          location: data.location,
        }
      )
      .then((res) => {
        console.log(res.data[0].woeid);
        setWoeid(res.data[0].woeid);
        setTimeout(() => setDisplay(true), 5000);
      })
      .catch((err) => {
        console.log(err);
      });
  }

  function handle(e) {
    const newdata = { ...data };
    newdata[e.target.id] = e.target.value;
    setData(newdata);
    console.log(newdata);
  }

  return (
    <div className="flex w-96 mx-auto mt-5 p-3 rounded-xl bg-blue-300">
      <form className="flex w-96 mx-auto p-3 rounded-xl bg-white">
        <div>
          <input
            className="text-gray-700"
            onChange={(e) => handle(e)}
            id="location"
            value={data.location}
            placeholder="Search for location"
            type="text"
          />
          <button
            className="bg-blue-900 text-gray-300 py-3 px-5 ml-12 rounded-xl"
            type="submit"
            onClick={(e) => submit(e)}
          >
            Search
          </button>
        </div>
      </form>
    </div>
  );
};

export default LocationSearch;

我的MainWeather.jsx:

import React, { useContext, useEffect, useState } from "react";
import axios from "axios";
import { DisplayContext } from "../App";
import Loader from "react-loader-spinner";

const MainWeather = ({ woeid }) => {
  const [temp, setTemp] = useState([]);
  const [icon, setIcon] = useState("");
  const { display } = useContext(DisplayContext);
  const [load, setLoad] = useState(false);

  useEffect(() => {
    axios
      .get(
        // "https://cors-anywhere.herokuapp.com/https://www.metaweather.com/api/location/" +
          "/api/location/" +
          woeid
      )
      .then((res) => {
        setLoad(true);
        console.log(res.data[0]);
        setIcon(res.data.consolidated_weather[0].weather_state_abbr);
        setTemp((prev) => {
          return [
            ...prev,
            res.data.consolidated_weather[0].the_temp,
            res.data.consolidated_weather[0].min_temp,
            res.data.consolidated_weather[0].max_temp,
            res.data.consolidated_weather[0].weather_state_name,
          ];
        });
      })
      .catch((err) => {
        console.log(err);
      });
  }, [woeid]);

  return (
    <>
      {display && (
        <div className="w-96 flex flex-col mx-auto p-3 mt-2 rounded-xl bg-blue-300">
          <img
            src={"/static/img/weather/" + icon + ".svg"}
            alt="Current weather icon"
            className="w-40 mx-auto pb-4"
          />
          <p className="mx-auto text-5xl pb-3">{Math.round(temp[0])}°C</p>
          <p className="mx-auto pb-1">
            {Math.round(temp[1])} / {Math.round(temp[2])}
          </p>
          <p className="mx-auto pb-2">{temp[3]}</p>
        </div>
      )}

      {!display && (
        <div>
          {load && (
            <div className="flex w-96 h-80 mx-auto mt-5 p-3 rounded-xl bg-blue-300">
              <Loader
                className="m-auto"
                type="Puff"
                color="#00BFFF"
                height={100}
                width={100}
                timeout={5000}
              />
            </div>
          )}

          {!load && (
            <div className="flex w-96 h-80 mx-auto mt-5 p-3 rounded-xl bg-blue-300">
              <h1 className="m-auto">Please enter a location</h1>
            </div>
          )}
        </div>
      )}
    </>
  );
};

export default MainWeather;

ExtraWeather.jsx 不相关。

如果我注释掉 MainWeather 并记录来自 LocationSearch 的返回,它会完美地返回到对象,但是一旦我引入 MainWeather 回来,我就会得到“CORS 标头 'Access-Control-Allow-Origin'缺失”错误。我已经尝试了所有可以找到的方法,包括在 Netlify 上托管应用程序、将代理更改为本地主机地址、将内容移动到不同的地方,我不确定我是否做得正确,但我确实尝试了反向代理。

还使用 herokuapp 和浏览器扩展程序确实可以解决问题,但我想要更永久的东西。

任何帮助将不胜感激。

【问题讨论】:

  • 错误信息到底是什么?
  • 跨源请求被阻止:同源策略不允许读取位于metaweather.com/api/location/44418 的远程资源。 (原因:CORS 标头“Access-Control-Allow-Origin”缺失)。

标签: javascript reactjs api axios netlify


【解决方案1】:

问题是响应被重定向到包含/ 后缀,即

HTTP/2 301
location: https://www.metaweather.com/api/location/44418/

这会导致您的浏览器重新尝试对该 URL 的请求,从而绕过您的代理。

尝试包含/ 后缀,例如

axios.get(`/api/location/${woeid}/`)

请记住,proxy 设置仅适用于本地开发。如果您要部署到 Netlify,请参阅 https://docs.netlify.com/routing/redirects/rewrites-proxies/#proxy-to-another-service


调试过程

某些东西正在引导您的浏览器尝试通过其完整 URL 访问 API,所以我怀疑是重定向。

我刚刚跑了

curl -v "https://www.metaweather.com/api/location/44418" -o /dev/null

并查看了响应状态和标头...

> GET /api/location/44418 HTTP/2
> Host: www.metaweather.com

< HTTP/2 301
< location: https://www.metaweather.com/api/location/44418/

发现差异是最困难的部分 ?

您可能已经在浏览器开发工具 Network 面板中看到了类似的内容;首先是对 /api/location/44418 的请求,带有 301 响应和 location 标头,然后是对未通过 CORS 检查的 https://www.metaweather.com/api/location/44418/ 的请求

【讨论】:

  • 哇,先生,非常感谢您,我为此烦恼了很久。感谢您对 Netlify 设置的提醒,我确实看到与 netlify.toml 有一些关系,但我并没有过多关注它。
  • 另外,如果您不介意我询问或指出我可以找到的地方,您怎么知道发生了什么事?
  • @BrandonBronkhorst 这是一个很好的问题。我已经用调试过程更新了我的答案
猜你喜欢
  • 2018-03-28
  • 2019-02-07
  • 2021-07-15
  • 1970-01-01
  • 1970-01-01
  • 2020-01-05
  • 2021-12-07
  • 2023-03-21
  • 2020-11-12
相关资源
最近更新 更多