AWS Lambda上传S3更新DynamoDB经API Gateway报KeyError
问题背景
尝试在同一个AWS Lambda函数中实现二进制图片上传至S3、同时更新DynamoDB表的逻辑,发起API调用时Postman返回如下错误:
{ "errorMessage": "'itemId'", "errorType": "KeyError", "requestId": "bccaead6-cb60-4a5e-9fc7-14ff25380451", "stackTrace": [ " File \"/var/task/lambda_function.py\", line 14, in lambda_handler\n s3_upload = s3.put_object(Bucket=bucket, Key=event[\"itemId\"] + \".png\", Body=decode_content)\n" ] }
事件入参设计为接收3个字符串参数,只要尝试访问这些参数就会触发上述错误;如果移除S3上传相关逻辑,仅访问参数更新DynamoDB则可正常运行。
使用的Lambda函数代码如下:
import json import boto3 import base64 dynamoclient = boto3.resource("dynamodb") s3 = boto3.client("s3") table = dynamoclient.Table("Items") bucket = "images" def lambda_handler(event, context): get_file_content = event["content"] decode_content = base64.b64decode(get_file_content) s3_upload = s3.put_object(Bucket=bucket, Key=event["itemId"] + ".png", Body=decode_content) table.put_item( Item={ 'itemID': event["itemId"], 'itemName': event['itemName'], 'itemDescription': event['itemDescription'] } ) return { "code":200, "message": "Item was added successfully" }
经反复验证,移除所有S3文件上传相关代码后,功能运行完全正常,可成功更新DynamoDB表。
API Gateway配置侧,已在Binary Media Types配置项中添加image/png类型,同时在Mapping Templates板块添加了image/png内容类型,对应模板配置如下:
{ "content": "$input.body" }
Postman POST请求头配置如下:
请求体的raw格式事件数据配置如下:
{ "itemId": "0fx170", "itemName": "Mouse", "itemDescription": "Smooth" }
同时在Postman的二进制文件上传板块选中了目标PNG文件。
故障根因
故障由两个配置冲突共同导致:
- API Gateway映射模板缺失字段:为
image/png内容类型配置的映射模板仅传递了content字段,完全没有包含itemId、itemName、itemDescription三个元数据字段,Lambda接收到的event结构里根本不存在这三个键,访问时自然触发KeyError。 - Postman请求逻辑矛盾:Postman的raw请求体和二进制文件上传是互斥选项,同时在raw栏填写JSON元数据、又在二进制上传栏选中PNG文件,实际发起请求时只会生效其中一种内容,不可能同时将JSON元数据和二进制文件放在同一个请求体中,被当前配置的映射模板正确解析。
- 移除S3逻辑后功能正常的原因:此时请求
Content-Type为application/json,API Gateway不会走为image/png配置的残缺映射模板,会直接将完整的JSON请求体透传给Lambda,三个字段都能正常读取,DynamoDB更新逻辑自然可以正常运行。
修复方案
二选一即可:
- 方案1(推荐):改用
multipart/form-data格式上传,这是同时传输文件和表单元数据的标准方式。需要在API Gateway开启multipart类型支持,修改映射模板同时解析表单中的文件字段和元数据字段,不要再用纯image/png的二进制直传方式。 - 方案2:如果坚持使用单请求体传输二进制文件,就不要在Postman中同时填写raw JSON和选择二进制文件。将
itemId、itemName、itemDescription三个参数放到URL查询参数或者自定义请求头中,修改image/png对应的映射模板,将三个参数一并传入Lambda,参考模板配置如下:
{ "content": "$input.body", "itemId": "$input.params('itemId')", "itemName": "$input.params('itemName')", "itemDescription": "$input.params('itemDescription')" }
配置完成后,Postman请求体仅保留二进制PNG文件,删除raw栏的JSON配置即可。
内容的提问来源于stack exchange,提问作者user15312648
相关产品推荐
相关产品推荐

