Next.js+React中axios响应无法存入state及网络错误排查
问题根因
你遇到的两个问题对应两个独立的逻辑错误,和请求头配置无关:
- 组件顶层直接调用
test()请求方法的问题
React函数组件每次状态更新触发重渲染时,都会从头执行一遍整个函数体逻辑。你直接在函数顶层调用请求方法,会形成「发请求→setProducts更新状态→触发重渲染→重渲染又调用test()发请求」的死循环;同时setProducts是异步批更新逻辑,你在调用test()后同步打印products,拿到的永远是当次渲染闭包里的初始空数组,等不到状态更新后的结果。 - 浏览器报
ERR_NETWORK、服务端能正常拿到响应的问题
你之前尝试的“开启CORS”操作完全无效:CORS规则是目标接口服务器通过响应头控制的,只有VTEX接口服务端配置了允许你的前端域名跨域访问,浏览器才会放行请求,你作为请求方在自己项目里配CORS头没有任何作用。服务端发请求不受浏览器同源策略限制,所以终端能正常拿到数据;浏览器直接请求VTEX域名时被跨域策略拦截,才会返回没有状态码的网络错误。
可行解决方案
优先选第一个方案,性能最好、逻辑最简单:
方案1:直接用Next.js服务端能力获取数据(推荐)
Next.js是全栈框架,数据请求直接放在服务端执行,彻底绕开浏览器跨域限制,不需要写useState、useEffect管理请求状态:
- 如果你用App Router,直接写异步服务端组件即可,组件代码默认跑在服务端:
// app/products/page.jsx import axios from 'axios' export default async function ProductsPage() { // 服务端直接请求VTEX接口,不存在跨域问题,鉴权信息写在这里也不会泄露到前端 const { data: products } = await axios.get('替换成你的VTEX商品搜索接口地址', { headers: { Accept: 'application/json' } }) return ( <div className="product-list"> {products.map(product => ( <div key={product.productId}>{product.productName}</div> ))} </div> ) }
- 如果你用Pages Router,用
getServerSideProps在服务端预取数据,再把数据作为props传给页面组件渲染即可。
方案2:写Next.js路由代理(必须客户端动态请求时用)
如果你的业务需要在客户端交互时动态拉取商品数据,就在Next.js里写一层同域名接口代理,浏览器只请求自己站点的接口,由Next.js服务端转发请求给VTEX,绕开跨域限制:
- 新建代理路由文件
app/api/vtex-products/route.js:
import axios from 'axios' export async function GET() { try { const { data } = await axios.get('替换成你的VTEX商品搜索接口地址', { headers: { Accept: 'application/json' } }) return Response.json(data) } catch (err) { return Response.json({ msg: '请求失败' }, { status: 500 }) } }
- 在客户端组件中请求本地代理接口,注意请求逻辑必须放在useEffect中,空依赖数组保证只在组件挂载时执行一次:
'use client' import { useState, useEffect } from 'react' import axios from 'axios' export default function ProductList() { const [products, setProducts] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const fetchData = async () => { try { // 请求同域名接口,无跨域问题 const { data } = await axios.get('/api/vtex-products') setProducts(data) } catch (err) { console.error(err) } finally { setLoading(false) } } fetchData() }, []) if (loading) return <div>商品加载中</div> return ( <div className="product-list"> {products.map(product => ( <div key={product.productId}>{product.productName}</div> ))} </div> ) }
避坑提示
- 所有请求、定时器这类副作用逻辑,不要直接写在组件函数顶层,必须放在
useEffect里或者绑定到用户交互事件(比如点击、输入事件)上,否则会触发无限重渲染。 - 涉及第三方接口鉴权的密钥、token,一律放在服务端代码里,不要写在客户端请求逻辑中,避免泄露给用户。
- 排查跨域问题时,先确认是浏览器端请求还是服务端请求,服务端请求不存在跨域限制,不需要做任何CORS配置。
内容的提问来源于stack exchange,提问作者pe.Math
相关产品推荐
相关产品推荐

