React+Serverless架构下CORS跨域请求拦截问题求助(配置无效)
问题描述
前端基于React、后端用Serverless架构发送API请求时,触发跨域错误:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost3000/auth. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 403.
已尝试两种方案但无效:
- 在处理函数返回值中手动添加CORS响应头(代码如下)
- 在
serverless.yml中配置allowedOrigins
此外,错误出现时页面会快速刷新。
现有代码
处理函数代码:
async function intentHandler(event, intents) { const request = JSON.parse(event.body); const intent = intents[request.intent]; const response = intent ? { status: 200, payload: await intent({ ...request.payload }) } : { status: 404, payload: "Invalid intent." }; return { headers: { "Content-Type": "application/json", "X-Requested-With": "*", "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Requested-With", "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Allow-Credentials": true, }, statusCode: response.status, body: JSON.stringify(response.payload), }; }
serverless.yml相关配置:
allowedOrigins: - http://localhost:2020 - http://localhost:3000
可能原因分析
- OPTIONS预检请求未被处理:浏览器跨域请求前会先发OPTIONS预检请求,如果后端没响应这个请求,直接触发CORS错误。你的处理函数可能只覆盖了GET/POST,没处理OPTIONS。
- Serverless配置位置错误:
allowedOrigins没嵌套在具体函数的cors配置下,导致框架未应用跨域规则。 - CORS头冲突:手动返回
Access-Control-Allow-Origin: *,和配置文件里的具体origin列表冲突,浏览器不认可。 - 前端请求方式错误:用HTML form的submit事件发请求会导致页面刷新,同时掩盖真实请求错误。
- 请求URL格式错误:错误信息里的
https://localhost3000/auth缺少冒号,正确格式应为https://localhost:3000/auth,错误URL会导致请求失败返回403。
解决方案
1. 正确配置Serverless的CORS规则
将allowedOrigins等配置嵌套在具体函数的HTTP事件cors字段下,让框架自动处理OPTIONS请求和响应头:
functions: intentHandler: # 替换为你的函数名称 handler: path/to/your/handler.intentHandler # 替换为实际文件路径 events: - http: path: auth # 对应你的请求路径 method: any # 覆盖GET、POST、OPTIONS等所有方法 cors: allowedOrigins: - http://localhost:2020 - http://localhost:3000 allowedHeaders: - Content-Type - X-Amz-Date - Authorization - X-Api-Key - X-Requested-With allowedMethods: - GET - POST - OPTIONS allowCredentials: true
配置完成后,可移除处理函数中手动添加的CORS headers,避免冲突。
2. 手动处理OPTIONS请求(自定义场景)
如果需要在函数内自定义OPTIONS响应逻辑,修改处理函数:
async function intentHandler(event, intents) { // 优先处理OPTIONS预检请求 if (event.httpMethod === 'OPTIONS') { return { statusCode: 200, headers: { "Content-Type": "application/json", "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Requested-With", "Access-Control-Allow-Origin": "http://localhost:3000", // 必须指定具体origin,不能用*(和credentials=true冲突) "Access-Control-Allow-Methods": "GET, POST, OPTIONS", "Access-Control-Allow-Credentials": true, }, body: JSON.stringify('OK'), }; } // 原有业务逻辑 const request = JSON.parse(event.body); const intent = intents[request.intent]; const response = intent ? { status: 200, payload: await intent({ ...request.payload }) } : { status: 404, payload: "Invalid intent." }; return { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "http://localhost:3000", "Access-Control-Allow-Credentials": true, }, statusCode: response.status, body: JSON.stringify(response.payload), }; }
3. 修复前端请求方式
改用AJAX方式(fetch/axios)发送请求,避免form submit导致页面刷新:
// React组件中fetch请求示例 const sendAuthRequest = async () => { try { const res = await fetch('https://your-serverless-endpoint/auth', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ intent: 'yourIntentName', payload: {} }), credentials: 'include', // 需要携带cookie时开启 }); const data = await res.json(); console.log('请求成功:', data); } catch (err) { console.error('请求失败:', err); } };
4. 修正请求URL
确认前端请求URL格式正确:https://localhost:3000/auth(注意localhost后的冒号),错误URL会导致请求到无效资源,返回403。
5. 验证CORS配置
用curl手动发送OPTIONS请求,检查响应头是否符合预期:
curl -X OPTIONS -H "Origin: http://localhost:3000" https://your-serverless-endpoint/auth -v
查看响应头中是否包含Access-Control-Allow-Origin、Access-Control-Allow-Methods等字段,且值与配置一致。
内容的提问来源于stack exchange,提问作者Mustafa Yusuf

