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

本地Vercel Serverless函数CORS问题排查求助

问题原因分析

你的核心问题是非简单请求(如带JSON的POST)触发的OPTIONS预检请求未被正确处理:

  1. 浏览器对非简单请求会先发OPTIONS预检,验证服务器是否允许跨域,但你的Serverless函数没有处理OPTIONS请求,导致预检返回非200状态码,触发CORS错误。
  2. vercel.json中的CORS头配置在vercel dev本地开发模式下,不会自动应用到Serverless函数的OPTIONS请求上——本地dev时函数由@vercel/node单独处理,该环节不会读取vercel.json的header规则。
  3. 从日志可见,OPTIONS请求时函数的handler(即console.log("2"))根本没执行,说明请求在到达函数逻辑前就被拦截返回了错误状态。

而GET请求能正常工作,是因为GET属于简单请求,浏览器不会发送OPTIONS预检,直接执行请求,函数逻辑能正常触发并返回200状态,自然不会触发CORS错误。


解决方法

方法1:在Serverless函数中手动处理OPTIONS请求

直接在函数逻辑里添加OPTIONS请求的处理分支,返回200状态和CORS头:

// api/test2.js
console.log("1");
export default function handler(request, response) {
  console.log("2");
  
  // 处理OPTIONS预检请求
  if (request.method === 'OPTIONS') {
    response.status(200)
      .setHeader('Access-Control-Allow-Credentials', 'true')
      .setHeader('Access-Control-Allow-Origin', '*')
      .setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT')
      .setHeader('Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version')
      .end();
    return;
  }

  // 处理正常业务请求
  return response.status(200).json({ text: 'I am a Serverless Function!' });
}
console.log("3");

方法2:完善官方的allowCors封装函数

确保官方提供的CORS封装包含OPTIONS请求的处理逻辑,避免每个函数重复写:

// 完整的allowCors封装
function allowCors(fn) {
  return async function(req, res) {
    // 设置CORS响应头
    res.setHeader('Access-Control-Allow-Credentials', 'true');
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT');
    res.setHeader('Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version');

    // 处理OPTIONS预检请求
    if (req.method === 'OPTIONS') {
      res.status(200).end();
      return;
    }

    // 执行原业务逻辑
    return await fn(req, res);
  };
}

// 你的业务handler
function handler(req, res) {
  return res.status(200).json({ message: '请求成功' });
}

export default allowCors(handler);

方法3:用Vite代理避免跨域

在Vite配置中添加代理,让前端请求和Vite dev服务器同域,彻底绕过CORS问题:

// vite.config.js
export default {
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true
      }
    }
  }
}

然后修改Axios请求路径,去掉域名:

await axios.post('/api/test1', {})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 20:13:18