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

使用预签名URL上传文件至AWS S3时遭遇403 Forbidden错误求助

AWS S3预签名URL上传文件出现403 Forbidden问题

我是AWS S3新手,正在搭建一套文件上传流程:用Python生成预签名URL,再通过前端JS借助该URL直接上传文件到S3。使用boto3库生成预签名URL,后端和前端代码如下,选择文件上传时出现"PUT url 403 (Forbidden)"错误,我怀疑问题出在前端PUT请求的代码块中。

后端Python代码

from flask_cors import CORS
import boto3
from flask import Flask, request, jsonify

app = Flask(__name__)

cors = CORS(app)

@app.route('/get-signed-url', methods=['POST'])
def get_signed_url():
    s3 = boto3.client(
        's3',
        aws_access_key_id='***',  
        aws_secret_access_key='***'  
    )

    # 获取POST请求中的数据
    data = request.get_json()
    name = data.get('name')

    # 设置URL参数
    params = {
        'Bucket': 'myprojecttt',  
        'Key': name,
        'Expires': 30 * 60, 
    }

    url = s3.generate_presigned_url(
        ClientMethod='put_object',
        Params=params
    )

    return jsonify({'url': url})

if __name__ == '__main__':
    app.run(debug=True)

前端JS代码

<input type="file" id="fileInput">
<button onclick="fetchData()">Upload</button>

<script>
    async function fetchData() {

        const fileInput = document.getElementById('fileInput');
        const file = fileInput.files[0];
        console.log(file)

        if (!file) {
            alert("Please select a file.");
            return;
        }

        try {
            const response = await fetch('http://localhost:5000/get-signed-url', {
                method: 'POST',
                body: JSON.stringify({ name: file.name }), // 将文件名发送至服务器
                headers: {
                    'Content-Type': 'application/json', // 设置请求内容类型
                },
            });

            if (!response.ok) {
                throw new Error(`HTTP error! Status: ${response.status}`);
            }

            const data = await response.json();
            const presignedUrl = data.url;
            console.log('Presigned URL:', presignedUrl);

            try {
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    body: file,
                    headers: {
                        'Content-Type': file.type,
                    },
                });

                if (response.ok) {
                    console.log('File uploaded successfully.');
                } 
                // else {
                //   console.error('Error:', response.status, response.statusText);
                // }
            } catch (error) {
                console.error('Error:', error);
            }
        } catch (error) {
            console.error('Error:', error);
        }
    } 
</script>

疑似问题代码块

const response = await fetch(presignedUrl, {
    method: 'PUT',
    body: file,
    headers: {
        'Content-Type': file.type,
    },

可能的原因及解决方法

1. 预签名URL未包含Content-Type参数,签名不匹配

预签名URL的签名会校验请求的Header信息,生成URL时未指定ContentType,但前端上传时添加了Content-Type Header,会触发签名验证失败。

解决方法:

  • 前端请求预签名URL时,同时传递文件类型:
    body: JSON.stringify({ name: file.name, contentType: file.type })
    
  • 后端生成URL时,在参数中加入ContentType:
    # 获取POST请求中的数据
    data = request.get_json()
    name = data.get('name')
    content_type = data.get('contentType')
    
    # 设置URL参数
    params = {
        'Bucket': 'myprojecttt',  
        'Key': name,
        'Expires': 30 * 60,
        'ContentType': content_type  # 添加该参数
    }
    

2. IAM用户或Bucket权限不足

确保生成预签名URL的IAM用户拥有s3:PutObject权限,同时Bucket Policy允许该操作。

示例Bucket Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::你的AWS账号ID:user/你的IAM用户名"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::myprojecttt/*"
        }
    ]
}

3. 文件名存在编码或特殊字符问题

如果文件名包含特殊字符,可能导致生成URL时的Key和实际请求的Key不匹配。可以对文件名进行URL编码后再传递给后端生成签名。

4. 前端请求存在多余Header

确保前端PUT请求的Header和预签名URL生成时指定的参数完全一致,不要添加额外的Header(比如X-Requested-With等),否则会破坏签名验证。


内容的提问来源于stack exchange,提问作者Quốc Khánh Nguyễn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 00:01:07