You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js使用预签名URL传视频至AWS S3遇501 Not Implemented错误

问题:使用预签名URL上传视频到AWS S3时遇到501错误

尝试通过预签名URL将视频文件上传至AWS S3,但收到status: 501, statusText: 'Not Implemented'错误。已参考相关问题尝试设置Content-Type和Content-Length,但问题依旧。

生成预签名URL的代码

var S3 = require('aws-sdk/clients/s3')

async function getS3UploadSignedUrl() {
    var s3 = new S3({
        accessKeyId: config.aws.accessKeyId,
        secretAccessKey: config.aws.secretAccessKey,
        region: config.aws.region,
        apiVersion: '2010-12-01'
    });
    
    let params = {
        Bucket: config.aws.s3Bucket,
        Key: 'myVideo.mp4',
        Expires: 60 * 60, // 单位:秒
        ContentType: 'video/mp4',
        ACL: 'public-read',
    }
    let signedUrl = await s3.getSignedUrl('putObject', params);
    console.log('signedUrl', signedUrl)
}

上传代码

const fs = require('fs');

const FILE_PATH = '/home/alok/Downloads/video.mp4';
const signedUrl = 'https://my pre signed url'

const fileStream = fs.createReadStream(FILE_PATH);
const contentLength = fs.statSync(FILE_PATH).size;

async function uploader() {
    var options = {
        method: "PUT",
        headers: { "content-type": "video/mp4" },
        body: fileStream,
        'Content-Length': contentLength
    }
    let response = await fetch(signedUrl, options)
    console.log(response)
}

uploader()

存储桶策略

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicRead",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::my-bucket/*"
        }
    ]
}

CORS配置

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "HEAD",
            "PUT",
            "POST"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "x-amz-server-side-encryption",
            "x-amz-request-id",
            "x-amz-id-2"
        ],
        "MaxAgeSeconds": 3000
    }
]

请问遗漏了什么配置或步骤,导致无法完成视频上传?


解决方法

1. 修正上传请求的Content-Length位置

上传代码中Content-Length被放在options根层级,这是错误的,它属于HTTP请求头,必须放在headers对象内,否则不会被识别为请求头发送。

修改后的上传代码:

async function uploader() {
    var options = {
        method: "PUT",
        headers: { 
            "content-type": "video/mp4",
            "Content-Length": contentLength // 移至headers中
        },
        body: fileStream
    }
    let response = await fetch(signedUrl, options)
    console.log(response)
}

2. 修正预签名URL生成逻辑

AWS SDK v2的getSignedUrl是同步方法,不需要加await,错误使用await可能导致生成无效URL。调整代码:

let signedUrl = s3.getSignedUrl('putObject', params);

3. 确认预签名URL使用正确的S3端点

如果预签名URL使用了存储桶的静态网站托管域名(如http://my-bucket.s3-website-us-east-1.amazonaws.com),会返回501错误——静态网站模式仅支持GET/HEAD请求。必须使用S3 REST API域名(如https://my-bucket.s3.us-east-1.amazonaws.com)生成预签名URL。

4. 确保请求头与预签名参数完全匹配

预签名时指定了ContentType: 'video/mp4',上传时的content-type头需保持一致(HTTP头不区分大小写,但建议完全匹配)。同时不要添加预签名参数中未包含的额外请求头,否则会触发签名验证失败。

5. 检查生成签名的IAM用户权限

生成预签名URL的IAM用户需要具备s3:PutObject和s3:PutObjectAcl权限(因为指定了ACL: public-read),需确保用户的IAM策略包含这些权限,而非仅依赖存储桶策略。

示例IAM策略:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::my-bucket/*"
        }
    ]
}

内容的提问来源于stack exchange,提问作者Alok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 09:52:51