如何使用Python requests将AWS S3对象作为HTTP POST请求的输入?
问题原因
s3.get_object(...)[Body].read()返回的是纯二进制字节串,而open('myFile.pdf', 'rb')返回的是带元数据的文件类对象。requests库的files参数接收文件对象时,会自动补全文件名、Content-Type等信息组装multipart/form-data格式的请求,直接传入裸字节串会导致这些必要的表单元信息缺失,目标接口无法正常解析文件内容。
解决方案1:手动补全表单元信息(小文件场景推荐)
requests的files参数支持传入(文件名, 文件内容, MIME类型)的元组格式,手动补充缺失的元数据即可正常调用:
import boto3 import requests s3 = boto3.client('s3') # 读取S3文件二进制内容 file_content = s3.get_object(Bucket=bucketName, Key=fileKeyName)['Body'].read() # 从S3 Key中提取文件名,也可自定义为任意名称 file_name = fileKeyName.split('/')[-1] # 传入元组格式的files参数,pdf文件的MIME类型为application/pdf,可根据实际文件类型调整 response = requests.post( url_endpoint, files={'files': (file_name, file_content, 'application/pdf')} )
如果不确定文件对应的MIME类型,可以省略第三个参数,requests会自动使用默认的application/octet-stream,绝大多数接口都可以兼容该类型。
解决方案2:流式传输(大文件场景推荐)
如果S3存储的文件体积较大,全量读取到内存会占用Lambda的运行内存资源,可以直接使用S3返回的StreamingBody类文件对象实现流式传输,不需要全量加载文件内容:
import boto3 import requests s3 = boto3.client('s3') s3_resp = s3.get_object(Bucket=bucketName, Key=fileKeyName) file_stream = s3_resp['Body'] file_name = fileKeyName.split('/')[-1] response = requests.post( url_endpoint, files={'files': (file_name, file_stream, 'application/pdf')} )
该方式不会占用额外内存存储文件内容,可避免大文件场景下触发Lambda的内存配额限制,传输性能也更优。
注意:AWS Lambda官方提供的Python运行时默认未预装requests库,若运行时报
ModuleNotFoundError,需要提前将requests及其依赖打包为Lambda层上传使用,或改用Python标准库urllib实现POST请求逻辑。
内容的提问来源于stack exchange,提问作者mionnaise
相关产品推荐
相关产品推荐

