使用Python+Lambda解压S3多层目录压缩包时报No Such Key错误
问题解决方案
你遇到的NoSuchKey错误和创建IO缓冲区的操作本身无关,该错误的核心含义是你传入的zip_key在指定S3存储桶中不存在。你观察到「仅含单个文件的压缩包运行正常、含多层目录的压缩包报错」,本质是两类压缩包的上传路径/文件名差异触发了S3事件通知的编码逻辑,和压缩包内部结构没有直接关联。
核心修复方案
S3事件通知返回的object.key默认是URL编码格式,如果你的压缩包文件名/上传路径包含空格、中文、特殊符号(甚至多层目录拼接时的特殊字符),会被编码为%XX格式,直接用编码后的key请求S3就会找不到对象。
修改代码如下:
- 首先导入URL解码模块
from urllib.parse import unquote_plus
- 修改
zip_key的取值逻辑,增加解码步骤
bucketname = event["Records"][0]['s3']['bucket']['name'] # 对S3返回的原始key做URL解码 raw_zip_key = event["Records"][0]['s3']['object']['key'] zip_key = unquote_plus(raw_zip_key) s3_uri = 's3://'+bucketname+'/'
辅助排查验证
- 增加日志打印确认key正确性,在调用
zip_obj.get()前添加打印逻辑:
执行后到Lambda对应的CloudWatch日志组查看打印值,和S3控制台中对应压缩包的完整key对比,确保完全一致(S3 key大小写敏感)。print(f"验证存储桶:{bucketname},验证压缩包key:{zip_key}") - 确认Lambda执行角色的S3读权限覆盖了对应路径的zip文件,没有权限边界或存储桶策略拦截GetObject请求。
额外代码优化建议
针对你当前的解压逻辑,可补充两个优化点避免后续报错:
- 跳过压缩包内的目录项:
z.namelist()会返回目录路径(结尾为/),直接上传空目录会抛出异常,可在循环中简化判断逻辑:for filename in z.namelist(): # 跳过目录项和Mac系统生成的隐藏文件目录 if filename.endswith('/') or '__MACOSX' in filename: continue s3_client.meta.client.upload_fileobj(z.open(filename),Bucket=bucketname,Key=f'output/{filename}') - 大体积压缩包适配:当前逻辑是将整个压缩包加载到Lambda内存,若压缩包体积超过Lambda分配的内存会触发OOM,可修改为流式处理减少内存占用。
内容的提问来源于stack exchange,提问作者user8738575
相关产品推荐
相关产品推荐

