NextJS中向S3预签名URL上传图片时如何设置/更新对象元数据
你当前的实现方案无法直接在前端PUT请求时更新元数据,原因是AWS S3预签名URL的签名逻辑会将生成URL时传入的所有参数(包括Metadata的字段和对应值)纳入校验,请求时参数和签名时不一致就会返回403错误。
方案1:请求预签名URL时传递原始文件名(推荐)
这是成本最低、最安全的实现方式,不需要额外操作即可完成元数据写入:
第一步:修改后端预签名接口
将原GET接口改为POST,接收前端传递的原始文件名、文件类型,生成预签名URL时直接填入对应的Metadata值:
// 修改后的后端代码 async function handler(req, res) { if (req.method === 'POST') { const { originalFileName, contentType } = req.body; const key = `content/${uuidv4()}.jpeg`; s3.getSignedUrl( 'putObject', { Bucket: 'assets', ContentType: contentType, Key: key, Expires: 5 * 60, Metadata: { 'file-name': originalFileName, } }, (err, url) => res.send({ key, url }) ); } }
第二步:修改前端上传逻辑
请求预签名接口时携带原始文件名和文件类型,上传时不需要额外传递x-amz-meta-file-name头:
// 修改后的前端代码 const [file, setFile] = useState(null); const onFileUpload = async (e) => { e.preventDefault(); if (!file) return; // 请求预签名URL时传递原始文件名和文件类型 const uploadConfig = await fetch('/api/upload', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ originalFileName: file.name, contentType: file.type }) }); const uploadURL = await uploadConfig.json(); await fetch(uploadURL.url, { body: file, method: 'PUT', headers: { 'Content-Type': file.type, }, }); };
方案2:上传完成后修改元数据(备用)
如果确实无法在请求预签名URL时拿到文件名,可以在文件上传完成后,调用后端接口通过S3的copyObject方法修改元数据:
- 前端上传完成后向后端发送请求,携带文件的key和需要设置的文件名
- 后端调用S3的copyObject接口,将源对象复制到同一个key,同时传入新的Metadata配置,设置
MetadataDirective: 'REPLACE'即可覆盖原有元数据
// 后端修改元数据示例代码 await s3.copyObject({ Bucket: 'assets', CopySource: `/assets/${key}`, Key: key, Metadata: { 'file-name': newFileName }, MetadataDirective: 'REPLACE' }).promise();
这个方案需要额外调用一次S3接口,仅适合特殊场景使用。
内容的提问来源于stack exchange,提问作者Optimus Prime Time
相关产品推荐
相关产品推荐

