如何使用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
相关产品推荐
相关产品推荐

