AWS SDK JS v3 React前端获取PutObject预签名URL参数配置问题
为PutObject操作生成预签名URL(AWS SDK JS v3)
以下配置基于Client与Command模式实现,可直接用于浏览器端图片上传场景。
一、client(S3Client实例)配置
注意:S3Client初始化逻辑必须放在后端服务(Node.js环境)执行,禁止把带AWS密钥的代码打包到前端,否则会泄露云账号权限造成资产损失
- 先安装依赖
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
- 初始化客户端示例
import { S3Client } from "@aws-sdk/client-s3"; const client = new S3Client({ region: "你的S3桶所在区域,例如ap-northeast-1", credentials: { accessKeyId: "你的AWS Access Key ID", secretAccessKey: "你的AWS Secret Access Key" }, // 若使用S3兼容存储(如MinIO)可添加以下两个参数,官方AWS S3无需配置 // endpoint: "你的兼容存储服务地址", // forcePathStyle: true });
生产环境建议把密钥、区域、桶名等配置放到环境变量中,不要硬编码在代码里。
二、putObjectParams(PutObjectCommand入参)配置
该参数用于声明上传对象的属性,常用配置项如下:
const putObjectParams = { Bucket: "你的S3桶名称", Key: "文件在桶内的存储路径,例如images/avatar/20240501_xxx.png", ContentType: "上传文件的MIME类型,例如image/png", // 必配,否则上传后文件默认是二进制流,浏览器访问会触发下载而非预览 // 可选配置:限制上传文件大小,例如限制最大5MB // ContentLength: 5 * 1024 * 1024, // 可选配置:若桶为私有读,需要文件公网可访问可添加该配置 // ACL: "public-read" };
三、完整实现示例
后端生成预签名URL逻辑(以Express框架为例)
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; const client = new S3Client({ region: process.env.AWS_S3_REGION, credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY } }); // 给前端调用的签名接口 app.get("/api/get-upload-url", async (req, res) => { const { fileName, fileType } = req.query; const fileKey = `upload/images/${Date.now()}_${fileName}`; const putObjectParams = { Bucket: process.env.AWS_S3_BUCKET, Key: fileKey, ContentType: fileType }; const command = new PutObjectCommand(putObjectParams); // expiresIn为签名有效期,单位秒,这里设为5分钟,建议根据业务场景尽量设短 const uploadUrl = await getSignedUrl(client, command, { expiresIn: 300 }); res.json({ uploadUrl, // 上传完成后的文件访问地址 fileUrl: `https://${process.env.AWS_S3_BUCKET}.s3.${process.env.AWS_S3_REGION}.amazonaws.com/${fileKey}` }); });
浏览器端上传逻辑
前端拿到后端返回的预签名URL后,直接发送PUT请求上传文件即可,不需要携带额外AWS认证信息:
const fileInput = document.querySelector("#avatarUpload"); fileInput.addEventListener("change", async (e) => { const file = e.target.files[0]; // 向自己的后端请求预签名URL const res = await fetch(`/api/get-upload-url?fileName=${encodeURIComponent(file.name)}&fileType=${file.type}`); const { uploadUrl, fileUrl } = await res.json(); // 上传文件到S3 await fetch(uploadUrl, { method: "PUT", headers: { "Content-Type": file.type // 这里的Content-Type必须和生成签名时填写的ContentType完全一致,否则会报403签名错误 }, body: file }); console.log("图片上传完成,访问地址:", fileUrl); });
常见踩坑提示
- 生成签名时配置的
ContentType必须和前端上传时携带的Content-Type请求头完全一致,否则会返回403权限错误 - 如果配置了
ContentLength参数,前端上传的文件大小必须和该值完全匹配,否则签名校验失败 - 如果上传时触发CORS错误,需要在S3桶的权限配置中添加对应CORS规则:
[ { "AllowedOrigins": ["https://你的前端业务域名"], "AllowedMethods": ["PUT"], "AllowedHeaders": ["Content-Type"], "ExposeHeaders": [] } ]
- 预签名URL本身有权限时效,过期后需要重新向后端请求新的URL
内容的提问来源于stack exchange,提问作者razer
相关产品推荐
相关产品推荐

