AWS API Gateway+Lambda发起DELETE请求出现CORS及内部服务错误
问题1:API DELETE方法返回内部错误原因及测试方式
错误原因
从CloudWatch日志可以明确两个核心报错诱因:
- 你在API Gateway测试、Postman测试时,将id放在查询参数中传递,此时API Gateway透传给Lambda的
event.body为null,你的代码直接执行JSON.parse(event.body)就会抛出SyntaxError: Unexpected token u in JSON at position 0异常,后续访问body.data也会抛出空指针错误。 - API Gateway测试和Lambda控制台测试的核心区别就是入参结构不同:Lambda控制台测试是你手动构造完整的event入参,你之前测试时主动填入了
body字段所以运行正常;而API Gateway触发时,会严格按照请求的实际内容填充event字段,查询参数存放在event.queryStringParameters,请求体才会存放在event.body,你测试时用了查询参数但代码只从body取值,自然会报错。
正确测试方式
- 如果你要沿用当前代码逻辑,测试时不要传查询参数,而是将
{"data":{"id":"1633613467228"}}放在DELETE请求的请求体中传递即可。 - 额外CORS错误说明:你返回头同时配置了
Access-Control-Allow-Origin: *和Access-Control-Allow-Credentials: true,这不符合CORS规范,二者不能共存,要么把Access-Control-Allow-Credentials改为false,要么把Access-Control-Allow-Origin替换为你的前端实际域名http://localhost:3000,同时需要在API Gateway中为DELETE方法开启CORS配置,添加OPTIONS预检请求的处理规则,否则浏览器预检请求失败就会抛出CORS错误。
问题2:axios传参及Lambda取值方式是否正确
你当前的写法逻辑本身没问题:axios.delete的第二个参数中传入data字段,确实会将数据放到DELETE请求的请求体中,只要API Gateway正确透传请求体给Lambda,body.data.id的取值方式就可以正常拿到id。
需要注意的是部分旧版API Gateway默认会过滤DELETE请求的请求体,你可以检查API Gateway的集成请求配置,确认开启了代理集成,勾选了透传请求体的选项。
优化后的Lambda代码参考
可以兼容请求体、查询参数两种传参方式,同时加错误捕获避免502错误:
const AWS = require('aws-sdk') const docClient = new AWS.DynamoDB.DocumentClient() exports.handler = async (event) => { console.log(event) let id; // 兼容两种传参方式 if(event.body) { try { let body = JSON.parse(event.body); id = body?.data?.id; } catch (e) { console.log('解析body失败', e) } } if(!id && event.queryStringParameters?.id) { id = event.queryStringParameters.id; } if(!id) { return { statusCode: 400, headers: { "Access-Control-Allow-Origin" : "http://localhost:3000", "Access-Control-Allow-Credentials" : true }, body: JSON.stringify({message: '缺少id参数'}) } } const scanItemPayload = { TableName: 'aws-training', Key:{ id } } try { const dynamoDBResponse = await docClient.delete(scanItemPayload).promise() console.log(dynamoDBResponse) return { body: JSON.stringify(dynamoDBResponse), statusCode: 200, headers: { "Access-Control-Allow-Origin" : "http://localhost:3000", "Access-Control-Allow-Credentials" : true, }, }; } catch (e) { console.error('删除失败', e) return { statusCode: 500, headers: { "Access-Control-Allow-Origin" : "http://localhost:3000", "Access-Control-Allow-Credentials" : true }, body: JSON.stringify({message: '删除失败', error: e.message}) } } };
内容的提问来源于stack exchange,提问作者defs
相关产品推荐
相关产品推荐

