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

如何使用JavaScript将上传文件保存到Amazon S3存储桶

实现方案

为了避免AWS访问密钥泄露,推荐采用Django后端生成S3预签名上传URL + 前端直接上传到S3的方案,不需要把敏感凭证写到前端代码中,安全合规。

第一步:后端Django侧开发

  • 先安装依赖包:
pip install boto3
  • 编写预签名URL生成接口,代码示例如下:
import boto3
from django.http import JsonResponse
from django.views.decorators.http import require_GET

# 配置参数可以放到Django settings.py中统一管理
AWS_ACCESS_KEY_ID = "你的AWS访问密钥ID"
AWS_SECRET_ACCESS_KEY = "你的AWS秘密访问密钥"
AWS_S3_BUCKET_NAME = "你的S3存储桶名称"
AWS_S3_REGION = "你的S3区域,例如ap-beijing"

@require_GET
def get_s3_presigned_url(request):
    # 获取前端传的文件名和文件类型
    file_name = request.GET.get("file_name")
    file_type = request.GET.get("file_type")
    
    s3_client = boto3.client(
        "s3",
        aws_access_key_id=AWS_ACCESS_KEY_ID,
        aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
        region_name=AWS_S3_REGION
    )
    
    # 生成有效期为1小时的预签名上传URL
    presigned_url = s3_client.generate_presigned_url(
        ClientMethod="put_object",
        Params={
            "Bucket": AWS_S3_BUCKET_NAME,
            "Key": f"upload/covers/{file_name}", # 自定义文件在S3中的存储路径
            "ContentType": file_type,
            "ACL": "public-read" # 若文件需要私有访问可删除该行
        },
        ExpiresIn=3600
    )
    
    # 返回预签名URL和上传后的S3文件访问地址
    return JsonResponse({
        "upload_url": presigned_url,
        "access_url": presigned_url.split("?")[0]
    })
  • 将接口注册到Django的urls.py中:
from django.urls import path
from .views import get_s3_presigned_url

urlpatterns = [
    # 其他现有路由
    path("api/get-s3-upload-url/", get_s3_presigned_url, name="get_s3_upload_url"),
]

第二步:S3桶配置补充

你已经可以通过Cyberduck正常访问存储桶,说明凭证权限基础没问题,只需要补充两个配置:

  • 给你的AWS凭证开通s3:PutObject权限,确保可以上传文件
  • 配置S3桶的跨域(CORS)规则,允许你的前端域名发起PUT请求,配置示例:
[
    {
        "AllowedHeaders": ["*"],
        "AllowedMethods": ["PUT", "GET"],
        "AllowedOrigins": ["你的前端域名,例如https://your-app.com"],
        "ExposeHeaders": []
    }
]

第三步:前端代码改造

你现有代码只有图片预览逻辑,补充上传逻辑后的代码如下:

function renderCover(value, row) {
    return `<img id="blah" alt="cover image" width="100" height="100" />
            <input type="file" 
                onchange="uploadCoverToS3(this.files[0])">`
}

async function uploadCoverToS3(file) {
    // 先渲染预览图
    document.getElementById('blah').src = window.URL.createObjectURL(file);
    
    try {
        // 1. 从后端获取预签名上传地址
        const urlRes = await fetch(`/api/get-s3-upload-url?file_name=${encodeURIComponent(file.name)}&file_type=${file.type}`);
        const { upload_url, access_url } = await urlRes.json();
        
        // 2. 直接上传文件到S3
        const uploadRes = await fetch(upload_url, {
            method: "PUT",
            body: file,
            headers: {
                "Content-Type": file.type
            }
        });
        
        if (uploadRes.ok) {
            console.log("上传成功,文件S3地址:", access_url);
            // 这里可以把access_url提交到后端保存到业务数据库
        } else {
            console.error("上传失败");
        }
    } catch (err) {
        console.error("上传异常:", err);
    }
}

注意事项

  • 你现有用于Cyberduck访问的AWS凭证可以直接用到Django配置中,不需要重新生成
  • 可以在后端生成S3存储的Key时添加UUID前缀,避免同名文件覆盖
  • 大文件上传可以改用分片上传方案,小体积照片使用上述方案完全足够
  • 绝对不要把AWS密钥直接写到前端代码中,会被盗用产生高额费用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 20:39:04