AWS Lambda boto3访问S3子目录对象报NoSuchKey错误
问题原因
S3是扁平结构的对象存储,不存在原生文件系统的"子目录"概念,控制台展示的层级路径,本质是用对象Key名称中的/字符做的视觉拆分,get_object接口本身完全支持访问带/的Key,不存在需要特殊配置才能访问"子目录"的情况。
你根目录下的code.py能正常拉取,说明Lambda执行角色的S3权限、桶名配置、boto3调用逻辑都是正确的,报NoSuchKey的核心原因是你传入的s3_key字符串和S3中存储的对象真实Key不完全匹配,常见触发场景:
- Key开头额外加了
/:S3的Key是对象在桶内的完整标识,开头带/会被识别为Key的第一个字符是斜杠的对象,这类对象不会在控制台正常展示,必然匹配失败。 - 存在控制台不可见的字符差异:比如路径段大小写不一致(S3 Key大小写敏感,
Problem_1和problem_1是完全不同的Key)、斜杠前后多了空格、特殊字符被自动URL编码(比如@被编码为%40,控制台仍显示为@但实际Key已经变化)、存在全角斜杠/全角@等肉眼无法区分的字符。 - 上传文件时路径和预期不一致:比如在控制台创建文件夹后上传文件,不小心把文件传到了其他层级路径下。
排查&修复方案
第一步:获取真实对象Key
不要依赖S3控制台的显示判断Key,控制台会对特殊字符做转义、对路径做视觉折叠,显示值和真实存储的Key可能存在差异。在Lambda代码中加入以下调试逻辑,打印指定前缀下所有对象的真实Key:
# 调试代码:列出指定前缀下的所有对象,打印带格式标识的真实Key paginator = s3_client.get_paginator('list_objects_v2') for page in paginator.paginate(Bucket=s3_buckt_name, Prefix="m.l"): for obj in page.get('Contents', []): # 用repr包装可以显示所有不可见字符、转义字符、多余空格 print(f"匹配到的真实对象Key: {repr(obj['Key'])}")
执行后从打印日志里复制完全一致的字符串作为s3_key传入即可。
第二步:修正代码中的隐藏问题
你原有代码直接把带/的s3_key作为本地文件路径写入,/tmp目录下不存在对应层级的子目录,即使GetObject成功也会触发文件写入错误,修正后的完整可运行代码如下:
import os import boto3 s3_client = boto3.client("s3", region_name='us-east-1') def lambda_handler(event, context): s3_buckt_name = event["s3_buckt_name"] s3_key = event["s3_key"] # 拉取S3对象 resp = s3_client.get_object(Bucket=s3_buckt_name, Key=s3_key) code_content = resp["Body"].read() # 递归创建本地对应目录,避免路径不存在导致写文件失败 local_save_path = os.path.join("/tmp", s3_key) os.makedirs(os.path.dirname(local_save_path), exist_ok=True) with open(local_save_path, "wb") as f: f.write(code_content) return { "status": "success", "saved_to": local_save_path }
传参注意事项
- 传入的Key不要手动做URL编码,boto3会自动处理特殊字符的编码逻辑,手动编码反而会导致匹配失败。
- 不要在Key开头加
/,直接传从根路径开始的Key字符串即可。 - 严格匹配Key的大小写、字符内容,不要有多余空格。
内容的提问来源于stack exchange,提问作者Mateo Lara
相关产品推荐
相关产品推荐

