You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
  }
}

差异原因

  1. 执行环境本质不同

    • getServerSideProps运行在服务器端:请求由Vercel服务器直接发往API服务器,属于服务器间的通信,完全不受浏览器的CORS规则约束,自然不会触发跨域校验。
    • 前端函数的fetch运行在浏览器端:请求从用户浏览器(源为https://www.myurl.com)发往https://myurl.com/api/products,两个域名(带www/不带www)属于不同源,触发浏览器的CORS校验;而你的API接口未返回允许该源的响应头,因此报错。
  2. 本地环境无异常的原因
    本地开发时,前端与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路由在服务器端转发请求,避免浏览器跨域:

  1. 在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);
}
  1. 修改前端函数的请求地址:
const refreshList = async () => {
  const resp = await fetch('/api/proxy-products');
  const products = await resp.json();
};

此方式下前端请求同域名的API路由,不会触发CORS,服务器端的转发也不受跨域规则限制。


内容的提问来源于stack exchange,提问作者SJ19

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 21:05:19