AWS API Gateway触发Lambda启用CORS后仍报500内部错误
问题排查:API Gateway调用Lambda返回500 Internal Server Error
问题现象
- Lambda控制台测试可正常执行DynamoDB写入、SMS发送两项逻辑
- 已在Lambda中配置CORS响应头,也在API Gateway控制台启用CORS并重新部署,但Postman、自有网站前端调用均返回错误
- Postman调用返回内容:
{"message": "Internal server error"} - 自有网站jQuery ajax POST调用返回500状态码,响应内容与Postman一致
- 直接访问API Gateway提供的接口端点,同样返回上述500错误
根因说明
代码存在4个核心问题,直接导致API调用失败:
- 异步逻辑时序错误:
dynamodb.putItem是异步非阻塞调用,发起调用后未等待执行完成就同步调用callback返回响应,异步操作的错误完全无法被捕获,API Gateway会因为Lambda执行上下文提前退出、返回结构不符合预期抛出通用500错误。 - Event结构解析错误:使用API Gateway Lambda代理集成时,POST请求的参数不会直接挂载在
event根节点,而是序列化为JSON字符串存放在event.body字段中。控制台测试时使用的是自定义测试事件,参数直接放在根节点因此可以正常运行,但实际API转发的请求中event.Id、event.Type均为undefined,DynamoDB写入时会因为缺少必填主键直接报错。 - 异步写法失效:在DynamoDB回调函数中返回Promise没有实际作用,外层代码没有接收、等待该Promise执行,SNS发送逻辑的执行结果和抛出的错误完全不会被处理。
- 未处理跨域预检请求:浏览器发起跨域POST请求前会自动发送OPTIONS方法的预检请求,现有代码未对OPTIONS方法做特殊处理,会尝试解析不存在的请求体、执行DynamoDB写入逻辑直接触发报错。
修复方案
1. 替换Lambda代码
统一使用async/await处理异步逻辑,正确解析请求结构、处理预检请求、捕获全局错误,修复后代码如下:
const AWS = require('aws-sdk'); // 推荐使用DocumentClient,无需手动指定字段类型N/S,减少参数错误 const dynamodb = new AWS.DynamoDB.DocumentClient(); const SNS = new AWS.SNS(); const tableName = "#####"; const snsParams = { PhoneNumber: 'mynumber####', Message: 'Someone wrote!' }; exports.handler = async (event) => { // 统一配置CORS响应头,所有响应(包括错误响应)都需携带 const corsHeaders = { "Access-Control-Allow-Headers" : "Content-Type", "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "OPTIONS,POST,GET" }; try { // 单独处理OPTIONS跨域预检请求 if (event.httpMethod === 'OPTIONS') { return { statusCode: 200, headers: corsHeaders, body: '' }; } // 解析API Gateway传递的JSON格式请求体 const requestBody = JSON.parse(event.body || '{}'); const { Id, Type } = requestBody; // 校验必填参数 if (!Id || !Type) { return { statusCode: 400, headers: corsHeaders, body: JSON.stringify({error: 'Missing required parameters: Id or Type'}) }; } // 等待DynamoDB写入完成 await dynamodb.put({ TableName: tableName, Item: { Id: Number(Id), Type: Type } }).promise(); console.log('Success in writing, now starting to send SMS'); // 等待SNS短信发送完成 await SNS.publish(snsParams).promise(); console.log('SMS alarm sent!'); // 正常返回响应 return { statusCode: 200, headers: corsHeaders, body: JSON.stringify({message: 'Operation completed'}) }; } catch (err) { console.log('Execution error: ', err); // 错误响应也需携带CORS头,避免前端无法读取错误信息 return { statusCode: 500, headers: corsHeaders, body: JSON.stringify({error: err.message}) }; } };
2. 配置校验
- 确认API Gateway集成类型为Lambda代理集成,如果使用非代理集成,需要在API Gateway侧单独配置响应映射模板,不能直接在Lambda中返回
statusCode/headers/body结构 - 修改配置后必须重新部署API到对应调用的stage(如dev/prod),仅保存配置不会生效
- 发起POST请求时需要携带
Content-Type: application/json请求头,请求体传递合法JSON结构,例如{"Id": 123, "Type": "test"} - 如果仍有报错,直接前往CloudWatch Logs查看对应Lambda调用的日志流,可获取具体错误栈,比API Gateway返回的通用500提示信息更精准
内容的提问来源于stack exchange,提问作者Gianluca Fontana
相关产品推荐
相关产品推荐

