AWS SDK生成S3对象读取预签名URL错误问题排查
解决AWS S3预签名URL因Key二次转义导致的NoSuchKey错误
问题背景
我使用AWS S3存储视频,通过预签名URL限制访问权限,但调用getVideoReadSignedUrl生成的URL访问时提示NoSuchKey错误:
- 数据库中存储的是多部分上传后
completeMultiPartUpload返回的Location,其中/被转义为%2F,示例URL:https://BUCKET_NAME.s3.REGION.amazonaws.com/videos%2F60e589xxxxxxxxx463c.mp4 - S3实际存储的对象Key为
videos/xxxxxxxxxxxxxxxxx.mp4,控制台获取的URL也使用原始/分隔 - 解析数据库URL时得到的Key是
videos%2Fxxxxxxxxxxxxxxxxx.mp4,传给getSignedUrl后会被二次转义为videos%252Fxxxxxxxxxxxxxxxxx.mp4,导致S3无法找到对应对象
解决方案
核心是在解析Key时解码URL编码的字符,将转义后的%2F还原为原始的/,确保传给S3的Key与实际存储的一致。
修正解析Key的函数
修改parseVideoKeyFromVideoUrl,添加decodeURIComponent解码步骤:
const parseVideoKeyFromVideoUrl = (object_url) => { const string_to_remove = "https://" + AWS_BUCKET_NAME + ".s3." + REGION + ".amazonaws.com/"; const encoded_object_key = object_url.replace(string_to_remove, ""); // 解码URL编码字符,还原%2F为/ const object_key = decodeURIComponent(encoded_object_key); return object_key; };
优化预签名URL生成函数(可选)
原函数用Promise封装回调,可改用AWS SDK提供的getSignedUrlPromise简化异步逻辑:
var getVideoReadSignedUrl = async function (url) { const key = awsS3Helpers.parseVideoKeyFromVideoUrl(url); try { const signedUrl = await s3.getSignedUrlPromise("getObject", { Bucket: AWS_BUCKET_NAME, Key: key, Expires: 300, }); console.log("生成的预签名URL:", signedUrl); return signedUrl; } catch (err) { console.error("生成预签名URL失败:", err); throw err; } };
效果说明
经过上述修改后,无论是数据库中存储的转义URL还是原始格式URL,都能解析出与S3实际存储一致的Key,生成的预签名URL不会出现二次转义问题,浏览器可正常访问视频资源。
内容的提问来源于stack exchange,提问作者AG_HIHI
相关产品推荐
相关产品推荐

