ReactJS CORS header 'Access-Control-Allow-Origin' 缺失
ReactJS CORS header ‘Access-Control-Allow-Origin’ missing
我正在使用第三方 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
记录 return 它 returns 到 object 完美但一旦我介绍MainWeather
返回“CORS header 'Access-Control-Allow-Origin' 丢失”错误。我已经尝试了所有我能找到的在 Netlify 上托管应用程序、将代理更改为本地主机地址、将内容移动到不同位置的所有方法,我不确定我是否正确地进行了操作,但我确实尝试了反向代理。
也使用 herokuapp 和浏览器扩展确实解决了这个问题,但我想要更永久的东西。
任何帮助将不胜感激。
问题是响应被重定向以包含 /
后缀,即
HTTP/2 301
location: https://www.metaweather.com/api/location/44418/
这会导致您的浏览器 re-attempt 绕过您的代理 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
并查看响应状态和 headers...
> GET /api/location/44418 HTTP/2
> Host: www.metaweather.com
< HTTP/2 301
< location: https://www.metaweather.com/api/location/44418/
发现差异是困难的部分
您可能已经在浏览器 dev-tools 网络 面板中看到了类似的内容;首先向 /api/location/44418
发送 301 响应请求和 location
header,然后向 https://www.metaweather.com/api/location/44418/
发送未通过 CORS 检查的请求
我正在使用第三方 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
记录 return 它 returns 到 object 完美但一旦我介绍MainWeather
返回“CORS header 'Access-Control-Allow-Origin' 丢失”错误。我已经尝试了所有我能找到的在 Netlify 上托管应用程序、将代理更改为本地主机地址、将内容移动到不同位置的所有方法,我不确定我是否正确地进行了操作,但我确实尝试了反向代理。
也使用 herokuapp 和浏览器扩展确实解决了这个问题,但我想要更永久的东西。
任何帮助将不胜感激。
问题是响应被重定向以包含 /
后缀,即
HTTP/2 301
location: https://www.metaweather.com/api/location/44418/
这会导致您的浏览器 re-attempt 绕过您的代理 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
并查看响应状态和 headers...
> GET /api/location/44418 HTTP/2
> Host: www.metaweather.com
< HTTP/2 301
< location: https://www.metaweather.com/api/location/44418/
发现差异是困难的部分
您可能已经在浏览器 dev-tools 网络 面板中看到了类似的内容;首先向 /api/location/44418
发送 301 响应请求和 location
header,然后向 https://www.metaweather.com/api/location/44418/
发送未通过 CORS 检查的请求