本地Vercel Serverless函数CORS问题排查求助
问题原因分析
你的核心问题是非简单请求(如带JSON的POST)触发的OPTIONS预检请求未被正确处理:
- 浏览器对非简单请求会先发OPTIONS预检,验证服务器是否允许跨域,但你的Serverless函数没有处理OPTIONS请求,导致预检返回非200状态码,触发CORS错误。
vercel.json中的CORS头配置在vercel dev本地开发模式下,不会自动应用到Serverless函数的OPTIONS请求上——本地dev时函数由@vercel/node单独处理,该环节不会读取vercel.json的header规则。- 从日志可见,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
相关产品推荐
相关产品推荐

