Lambda上传至S3的JPG文件损坏问题排查求助
问题分析与解决方案
你的S3里的文件只有162字节且无法打开,核心原因是你下载到的根本不是目标JPG图片,而是一个错误响应页面(比如403/404的HTML提示,或者JSON格式的错误信息)。下面具体拆解问题和解决办法:
为什么会出现这种情况?
- 请求被目标网站拦截:你使用了
verify=False跳过SSL验证,但很多网站会检查请求的User-Agent(默认requests的UA是python-requests/版本号,很容易被识别为爬虫),或者需要其他身份验证,导致网站返回错误页面而非图片。
- 请求被目标网站拦截:你使用了
- 没有检查响应状态:你的代码直接读取
response.content,但如果请求失败(比如返回4xx/5xx状态码),你根本没察觉到,直接把错误内容上传到了S3。
- 没有检查响应状态:你的代码直接读取
- stream模式下的内容读取问题:虽然
response.content在stream模式下也能获取内容,但如果响应是分块传输的,这种方式可能无法完整获取所有数据,不过这个概率相对较低,核心还是前两个问题。
- stream模式下的内容读取问题:虽然
修复步骤
1. 先排查请求是否成功
在代码中添加状态码检查,打印错误内容,确认问题所在:
import boto3 import requests import contextlib from io import BytesIO url = 'https://somesite.com/11/frame.jpg?abs_begin=2019-08-29T05:18:26Z' bucket_name = 'your-bucket-name' s3 = boto3.client('s3') with contextlib.closing(requests.get(url, stream=True, verify=False)) as response: # 先打印状态码,确认请求是否成功 print(f"请求状态码: {response.status_code}") if response.status_code != 200: # 打印错误响应内容,看看网站返回了什么 print(f"错误响应内容: {response.text}") # 这里可以抛出异常或者终止流程 raise Exception(f"请求失败,状态码: {response.status_code}") fp = BytesIO(response.content) s3.upload_fileobj(fp, bucket_name, 'my-dir/test_img.jpg')
运行这段代码后,查看Lambda的日志,就能知道是请求被拦截还是其他错误。
2. 添加模拟浏览器的请求头
如果日志显示是403 Forbidden,大概率是User-Agent的问题,添加一个浏览器的UA即可:
headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' } with contextlib.closing(requests.get(url, stream=True, verify=False, headers=headers)) as response: response.raise_for_status() # 自动抛出HTTP错误 fp = BytesIO(response.content) s3.upload_fileobj(fp, bucket_name, 'my-dir/test_img.jpg')
3. 优化stream模式下的内容读取(可选但推荐)
使用iter_content分块读取内容,既节省内存,也能确保完整获取数据:
with contextlib.closing(requests.get(url, stream=True, verify=False, headers=headers)) as response: response.raise_for_status() fp = BytesIO() # 分块读取,每块8KB for chunk in response.iter_content(chunk_size=8192): if chunk: # 跳过空块 fp.write(chunk) fp.seek(0) # 重置文件指针到开头,否则S3会上传空内容 s3.upload_fileobj(fp, bucket_name, 'my-dir/test_img.jpg')
额外注意事项
- Lambda执行环境中,如果你的代码依赖
requests,需要确保把它打包到部署包或者使用Lambda层(因为默认Lambda环境没有requests库)。 - 尽量避免使用
verify=False,除非你确定目标网站的SSL证书有问题,否则会有安全风险。
内容的提问来源于stack exchange,提问作者NorwegianClassic
相关产品推荐
相关产品推荐

