使用API Gateway和Lambda上传文件至S3时遇ASCII字符错误求助
问题:API Gateway+Lambda上传MP3到S3报错:ValueError: string argument should contain only ASCII characters
尝试使用API Gateway和Lambda将文件上传至S3,Lambda环节前流程均正常运行,Lambda代码如下:
import base64 import boto3 import os s3_client = boto3.client('s3') bucket_name = os.environ['S3_BUCKET_NAME'] def lambda_handler(event, context): contend_decode = base64.b64decode(event['body']) response = s3_client.put_object(Bucket=bucket_name, Body=contend_decode) print(response) return { 'statusCode': 200, 'body': 'File uploaded' }
上传MP3文件时收到如下错误:
[ERROR] ValueError: string argument should contain only ASCII characters Traceback (most recent call last): File "/var/task/lambda_function.py", line 10, in lambda_handler contend_decode = base64.b64decode(event['body']) File "/var/lang/lib/python3.8/base64.py", line 80, in b64decode s = _bytes_from_decode_data(s) File "/var/lang/lib/python3.8/base64.py", line 39, in _bytes_from_decode_data raise ValueError('string argument should contain only ASCII characters') [ERROR] ValueError: string argument should contain only ASCII characters Traceback (most recent call last): File "/var/task/lambda_function.py", line 10, in lambda_handler contend_decode = base64.b64decode(event['body']) File "/var/lang/lib/python3.8/base64.py", line 80, in b64decode s = _bytes_from_decode_data(s) File "/var/lang/lib/python3.8/base64.py", line 39, in _bytes_from_decode_data raise ValueError('string argument should contain only ASCII characters')
编辑补充:事件内容示例
{ "resource": "/upload", "path": "/upload", "httpMethod": "POST", "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", "CloudFront-Forwarded-Proto": "https", "CloudFront-Is-Desktop-Viewer": "true", "CloudFront-Is-Mobile-Viewer": "false", "CloudFront-Is-SmartTV-Viewer": "false", "CloudFront-Is-Tablet-Viewer": "false", "CloudFront-Viewer-ASN": "5410", "CloudFront-Viewer-Country": "FR", "Content-Type": "audio/mpeg", "Host": "um8xxxxpxx.execute-api.eu-west-1.amazonaws.com", "Postman-Token": "fe49e15f-82c6-44c7-8399-4b6fba9b9abc", "User-Agent": "PostmanRuntime/7.29.2", "Via": "1.1 12bc6711250373a4xxxxxxxxxx44504.cloudfront.net (CloudFront)", "X-Amz-Cf-Id": "5Zv2MVCxxxxxxxxxxxxyzMuv_CfIAxxxxxxxxxxxxJyz4JtHb-QImYZGQ==", "X-Amzn-Trace-Id": "Root=1-6383d306-4e81300e0000000c3262b7a45", "x-api-key": "g4KOPDl5zoB0E2QBpAAXSaESDFyGkR38f000", "X-Forwarded-For": "1XX.XX9.2XX.XX9, 1XX.XX6.XX5.XXX", "X-Forwarded-Port": "443", "X-Forwarded-Proto": "https" }, "multiValueHeaders": { "Accept": [ "*/*" ], "Accept-Encoding": [ "gzip, deflate, br" ], "CloudFront-Forwarded-Proto": [ "https" ], "CloudFront-Is-Desktop-Viewer": [ "true" ], "CloudFront-Is-Mobile-Viewer": [ "false" ], "CloudFront-Is-SmartTV-Viewer": [ "false" ], "CloudFront-Is-Tablet-Viewer": [ "false" ], "CloudFront-Viewer-ASN": [ "5410" ], "CloudFront-Viewer-Country": [ "FR" ], "Content-Type": [ "audio/mpeg" ], "Host": [ "um8xxxxpxx.execute-api.eu-west-1.amazonaws.com" ], "Postman-Token": [ "fDDDDf-82c8-44c9-DDD1-4b6f9QASFF9abc" ], "User-Agent": [ "PostmanRuntime/7.29.2" ], "Via": [ "1.1 12bVASD16aeca2DDD44504.cloudfront.net (CloudFront)" ], "X-Amz-Cf-Id": [ "5Zv2MVCnaDDDzMuv_CfIA6iC89CiUnjDDDAZXAb-QImYZGQ==" ], "X-Amzn-Trace-Id": [ "Root=1-6383AZDD-4e81002e022374c326hu8a45" ], "x-api-key": [ "g4KOPDl5zoBia3cT4pYMkynzyGkX00aa" ], "X-Forwarded-For": [ "1XX.XX9.2XX.XX9, 1XX.XX6.XX5.XXX" ], "X-Forwarded-Port": [ "443" ], "X-Forwarded-Proto": [ "https" ] }, "queryStringParameters": "None", "multiValueQueryStringParameters": "None", "pathParameters": "None", "stageVariables": "None", "requestContext": { "resourceId": "adddazq", "resourcePath": "/upload", "httpMethod": "POST", "extendedRequestId": "cR3o-zddEFgazz=", "requestTime": "27/Nov/2022:21:13:42 +0000", "path": "/dev/upload", "accountId": "114782879802", "protocol": "HTTP/1.1", "stage": "dev", "domainPrefix": "ua8xjwxraf", "requestTimeEpoch": 1669583622098, "requestId": "23e099f9-eda4-42b2-8b4f-b1aaea589978", "identity": { "cognitoIdentityPoolId": "None", "cognitoIdentityId": "None", "apiKey": "h4KOPDl5zoqsdT4pYMkynzdddaz8f95560", "principalOrgId": "None", "cognitoAuthenticationType": "None", "userArn": "None", "apiKeyId": "z887qsddox4", "userAgent": "PostmanRuntime/7.29.2", "accountId": "None", "caller": "None", "sourceIp": "176.139.21.129", "accessKey": "None", "cognitoAuthenticationProvider": "None", "user": "None" }, "domainName": "um8xxxxpxx.execute-api.eu-west-1.amazonaws.com", "apiId": "um8xxxxpxx" }, "body": "\x04\x08-P�\x10,Gh�m\x0c\x06K����Te�U�-��\r\x01�Y��l�,3�\x11�Q�4$�........6��\x1872Ip�d�p\x1d�M�PX�0`�x�0����d�\x0f�\x0c.ǃ��\x12\x00\x00\r \x00\x00\x01\x18��........", "isBase64Encoded": "False" }
注:仅展示了body中的部分字符用于演示。
解决方案
问题原因
API Gateway收到二进制MP3请求时,未将其编码为base64格式,而是直接以原始二进制字符的形式传递给Lambda。从事件中的isBase64Encoded: "False"可以确认这一点。此时event['body']包含大量非ASCII字符,而base64.b64decode仅能处理ASCII格式的base64字符串,因此触发报错。
修复方式(二选一即可)
方式一:修改API Gateway配置,开启二进制请求的base64编码
- 进入AWS控制台的API Gateway服务,找到对应的API
- 切换到设置(Settings)页面,在Binary Media Types中添加
audio/mpeg(如果需要支持所有二进制类型,可添加*/*) - 重新部署API到对应阶段
方式二:修改Lambda代码,直接处理原始二进制内容
无需对event['body']进行base64解码,直接将字符串转换为字节即可,因为latin-1编码可准确映射每个字符到对应的字节,不会丢失原始数据:
import boto3 import os s3_client = boto3.client('s3') bucket_name = os.environ['S3_BUCKET_NAME'] def lambda_handler(event, context): # 将原始body字符串转为字节 file_content = event['body'].encode('latin-1') response = s3_client.put_object(Bucket=bucket_name, Body=file_content) print(response) return { 'statusCode': 200, 'body': 'File uploaded' }
内容的提问来源于stack exchange,提问作者Youcef LAIDANI
相关产品推荐
相关产品推荐

