React项目调用CoinGecko API遇CORS标头缺失错误求助
解决React调用CoinGecko API的CORS错误
你遇到的CORS错误是浏览器同源策略限制导致的——直接从http://localhost:3000访问CoinGecko API时,对方服务器未返回允许跨域的响应头。下面是几种可行的解决方法:
方法1:校验API地址与请求配置
首先确认CoinList函数生成的请求URL完全正确,可直接在浏览器地址栏访问该URL,验证是否能正常返回JSON数据。同时删除axios请求中的crossDomain: true配置(浏览器环境下该参数无效,反而可能干扰请求):
const fetchCoins = async () => { setLoading(true); try { // 移除crossDomain配置 const { data } = await axios.get(CoinList(currency)); setCoins(data); } catch (error) { console.error("Error fetching coins:", error); } finally { setLoading(false); } };
方法2:配置React开发代理
通过本地代理转发请求,绕过浏览器的CORS限制,步骤如下:
- 安装代理依赖:
npm install http-proxy-middleware --save-dev
- 在项目根目录的
src文件夹下创建setupProxy.js文件,添加代理配置:
const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = function(app) { app.use( '/coingecko-api', createProxyMiddleware({ target: 'https://api.coingecko.com/api/v3', changeOrigin: true, pathRewrite: { '^/coingecko-api': '', // 移除前缀,转发到目标API地址 }, }) ); };
- 修改请求地址为代理路径,比如调整
CoinList函数或直接修改请求URL:
// 假设原来的CoinList返回完整API地址,现在改为代理路径 const CoinList = (currency) => `/coingecko-api/coins/markets?vs_currency=${currency}&order=market_cap_desc&per_page=100&page=1&sparkline=false`;
- 重启React开发服务器,代理自动生效。
方法3:确认API访问限制
CoinGecko公开API支持无密钥访问,但有请求频率限制(每分钟10-30次)。如果上述方法无效,可检查是否触发了频率限制,或者尝试在请求中添加Accept: application/json头:
const { data } = await axios.get(CoinList(currency), { headers: { 'Accept': 'application/json' } });
修改后的完整组件代码示例
import axios from 'axios'; import React, { useEffect, useState } from 'react'; import { CoinList } from '../config/api'; import { CrytpoState } from '../CryptoContext'; import { Container, LinearProgress, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, ThemeProvider, Typography, createTheme, makeStyles } from '@material-ui/core'; import { useNavigate} from "react-router-dom"; const CoinsTable = () => { const [coins, setCoins] = useState([]); const [loading, setLoading] = useState(false); const [search, setSearch] = useState(""); const history=useNavigate(); const {currency}=CrytpoState(); const fetchCoins = async () => { setLoading(true); try { // 移除crossDomain配置,添加请求头(可选) const { data } = await axios.get(CoinList(currency), { headers: { 'Accept': 'application/json' } }); setCoins(data); } catch (error) { console.error("Error fetching coins:", error); } finally { setLoading(false); } }; useEffect(() => { fetchCoins(); }, [currency]) const darkTheme= createTheme({ palette:{ primary:{ main:"#fff", }, type:"dark", }, }); const handleSearch=()=>{ return coins.filter( (coin)=> coin.name.toLowerCase().includes(search.toLowerCase()) || coin.symbol.toLowerCase().includes(search.toLowerCase()) ); }; const useStyles=makeStyles(()=>({ row:{ cursor: 'pointer', '&:hover': { backgroundColor: '#131111' } }, })); const classes=useStyles(); return ( <ThemeProvider theme={darkTheme}> <Container style={{ textAlign:"center" }}> <Typography variant="h4" style={{ margin:18, fontFamily:"Montserrat", }}> CryptoCurrency Prices by Market Cap! </Typography> <TextField label="Search For a Crypto Currency..!" variant="outlined" style={{ marginBottom:20, width:"100%" }} onChange={(e)=>setSearch(e.target.value)} /> <TableContainer> {loading?( <LinearProgress style={{backgroundColor:"gold"}} /> ) :( <Table> <TableHead style={{backgroundColor:"#EEBC1D"}}> <TableRow> {["Coin","Price","24h Change","Market Cap"].map((head)=>( <TableCell style={{ color:"black", fontWeight:700, fontFamily:"Montserrat", }} key={head} align={head==="Coin"? "": "right"} >{head}</TableCell> ))} </TableRow> </TableHead> <TableBody> {handleSearch().map((row)=>{ const profit=row.price_change_percentage_24h>0; return( <TableRow onClick={()=>history(`/coins/${row.id}`)} className={classes.row} key={row.id}> <TableCell component="th" scope="row" style={{ display:"flex", gap:15, }}> <img src={row?.image} alt={row.name} height="50" style={{ marginBottom:10 }} /> <div style={{ display:"flex", flexDirection:"column", }}> <span style={{ textTransform:"uppercase", fontSize:22, }}> {row.symbol} </span> <span style={{color:"darkgrey"}}> {row.name} </span> </div> </TableCell> <TableCell align="right"> {row.current_price.toLocaleString()} {currency} </TableCell> <TableCell align="right" style={{ color: profit ? 'rgb(14, 203, 129)' : 'red', fontWeight: 700 }}> {profit ? '+' : ''}{row.price_change_percentage_24h.toFixed(2)}% </TableCell> <TableCell align="right"> {row.market_cap.toLocaleString()} {currency} </TableCell> </TableRow> ); })} </TableBody> </Table> )} </TableContainer> </Container> </ThemeProvider> ) } export default CoinsTable;
内容的提问来源于stack exchange,提问作者prem jadwani
相关产品推荐
相关产品推荐

