NextJS/ReactJS部署Vercel生产环境仅出现CORS跨域问题求助
问题:前端调用API遇CORS错误,但getServerSideProps调用正常(仅Vercel生产环境)
在Vercel生产环境中,前端函数调用API接口时出现CORS错误,但使用getServerSideProps()调用则完全正常;本地开发环境无任何异常。
CORS错误信息
Access to fetch at 'https://myurl.com/api/products' from origin 'https://www.myurl.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
可正常运行的代码(getServerSideProps)
export async function getServerSideProps() { const resp = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/products`); const products = await resp.json(); return { props: { products } }; }
引发错误的前端函数代码
const refreshList = async () => { const resp = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/products`); // 此处触发错误 const products = await resp.json(); };
产品查询API接口代码
export default async function handler(req, res) { if (req.method == "GET") { const products = await prisma.product.findMany(); return res.send(products); } }
差异原因
执行环境本质不同
getServerSideProps运行在服务器端:请求由Vercel服务器直接发往API服务器,属于服务器间的通信,完全不受浏览器的CORS规则约束,自然不会触发跨域校验。- 前端函数的
fetch运行在浏览器端:请求从用户浏览器(源为https://www.myurl.com)发往https://myurl.com/api/products,两个域名(带www/不带www)属于不同源,触发浏览器的CORS校验;而你的API接口未返回允许该源的响应头,因此报错。
本地环境无异常的原因
本地开发时,前端与API通常共享同一域名(如localhost:3000),或者Next.js默认的代理机制会将/api请求转发到本地服务器,不存在跨域场景,所以不会触发CORS校验。
解决办法
方法1:给API接口添加CORS响应头
修改API接口代码,添加允许指定源的CORS响应头:
export default async function handler(req, res) { // 允许指定源跨域请求 res.setHeader('Access-Control-Allow-Origin', 'https://www.myurl.com'); // 可选:支持更多请求方法和自定义头 res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // 处理浏览器OPTIONS预检请求 if (req.method === 'OPTIONS') { return res.status(200).end(); } if (req.method === "GET") { const products = await prisma.product.findMany(); return res.send(products); } }
若需支持多个源,可动态判断请求头的origin字段:
const allowedOrigins = ['https://www.myurl.com', 'https://myurl.com']; const origin = req.headers.origin; if (allowedOrigins.includes(origin)) { res.setHeader('Access-Control-Allow-Origin', origin); }
方法2:使用Next.js API路由做代理
利用Next.js的API路由在服务器端转发请求,避免浏览器跨域:
- 在
pages/api目录下新建proxy-products.js:
export default async function handler(req, res) { const resp = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/products`); const products = await resp.json(); res.send(products); }
- 修改前端函数的请求地址:
const refreshList = async () => { const resp = await fetch('/api/proxy-products'); const products = await resp.json(); };
此方式下前端请求同域名的API路由,不会触发CORS,服务器端的转发也不受跨域规则限制。
内容的提问来源于stack exchange,提问作者SJ19
相关产品推荐
相关产品推荐

