AWS SAM Local本地文件上传时出现UnicodeDecodeError问题求助
看起来你遇到的是AWS SAM Local模拟API Gateway时,处理前端multipart文件上传的编码兼容问题——Postman能正常工作但前端不行,核心错误是UnicodeDecodeError,咱们一步步来分析和解决:
问题根源分析
错误提示的0xc4字节是典型的非UTF-8二进制内容(比如图片、压缩包这类文件里很常见),你的代码里有一处关键逻辑触发了这个问题:
body_bytes = base64.b64decode(event['body']) if event.get('isBase64Encoded') else event['body'].encode('utf-8')
当SAM Local模拟API Gateway时,前端上传的二进制body可能没有被正确标记为isBase64Encoded,但event['body']里直接包含了非UTF-8的原始字节内容。这时候你用encode('utf-8')去处理,就会触发编码错误——因为非UTF-8字节无法被安全转成UTF-8字符串再编码。
而Postman能正常工作,是因为它发送的请求格式更符合API Gateway的标准,SAM Local正确标记了isBase64Encoded,你的代码能正确解码base64内容。
修复步骤
1. 修复body二进制数据的处理逻辑
把parse_multipart函数中的body_bytes获取逻辑替换为以下代码,用latin-1编码处理非base64的情况——latin-1是单字节编码,能完整保留原始字节内容,不会出现编码错误:
# 修复后的body_bytes处理逻辑 import base64 body_bytes = base64.b64decode(event['body']) if event.get('isBase64Encoded') else event['body'].encode('latin-1')
2. 配置SAM Local的API Gateway二进制媒体类型
确保你的SAM模板(template.yaml)中,API Gateway资源配置了支持multipart/form-data的二进制媒体类型,让SAM Local正确识别并处理二进制请求:
Resources: # 替换成你实际的API资源名称 YourServerlessApi: Type: AWS::Serverless::Api Properties: # 保留你原有其他配置... BinaryMediaTypes: - multipart/form-data - application/octet-stream # 可选,覆盖通用二进制类型
3. 重启SAM Local服务
修改模板后,需要重启SAM Local的API服务,确保配置生效:
sam local stop sam local start-api
额外优化建议
为了让你的parse_multipart函数更健壮,还可以优化文件名解析逻辑,支持非英文字符的文件名(符合RFC 5987标准的编码格式),替换原有的filename解析代码:
# 优化后的文件名解析逻辑 from email.header import decode_header if b"filename=" in disposition: filename = None # 先处理RFC 5987标准的filename*编码格式 if b"filename*=" in disposition: for part in disposition.split(b';'): part = part.strip() if part.startswith(b'filename*='): encoded_filename = part.split(b'filename*=')[1].decode() charset, _, fname = encoded_filename.partition("''") try: filename = fname.encode('latin-1').decode(charset) except (UnicodeDecodeError, LookupError): filename = fname break # 若filename*不存在,再用原逻辑兼容旧格式 if not filename: try: filename = disposition.split(b'filename=')[1].strip(b'"').decode("utf-8") except UnicodeDecodeError: filename = disposition.split(b'filename=')[1].strip(b'"').decode("utf-8", "replace")
测试验证
完成以上修改后,重新用前端上传文件到SAM Local的API,应该就能避免UnicodeDecodeError,和Postman一样正常处理文件上传了。
内容来源于stack exchange

