使用fetch上传文件到兼容S3的DO Spaces时出现403 Forbidden与CORS错误
问题根因与解决方案
1. 签名不匹配(SignatureDoesNotMatch)核心原因
S3协议预签名PUT请求的校验规则为:签名计算时用到的所有参数必须和最终请求传递的参数完全一致,但凡出现多传、漏传、值不一致的情况都会直接返回签名不匹配。
你的后端生成预签名URL时,已经把ContentType: application/pdf和ACL: public-read两个参数纳入了签名计算,生成的URL里已经带有Content-Type和x-amz-acl的查询参数,前端上传时又在Header里重复传递了这两个值,导致S3校验时判定参数和签名时不一致,触发403错误。
另外从报错日志可以看到,请求URL里的Content-Type值为application/json,和后端设置的application/pdf不一致,说明后端生成签名时的参数可能存在被其他逻辑覆盖的问题,需要同步检查。
2. 具体修复步骤
前端代码修改
删除PUT请求Header里的Content-Type和x-amz-acl两个字段,所有签名参数已经包含在预签名URL中,不需要额外传递:
import { api } from './api'; export const getAwsUrl = async (name: string, base64cv: string) => { let binaryFile = base64cv; if (binaryFile.includes('base64,')) { binaryFile = base64cv.slice(base64cv.indexOf('base64,') + 7); } const uploadCvOptions = { method: 'PUT', body: Buffer.from(binaryFile, 'base64'), }; let res; let shouldFinallyTrigger = true; try { res = await api.mutation({ uploadCv: [{ cvInput: { name: name } }, { downloadUrl: true, putUrl: true }], }); } catch (err) { if (err) { shouldFinallyTrigger = false; } } finally { if (shouldFinallyTrigger) { await fetch(res?.uploadCv.putUrl as string, uploadCvOptions); return res?.uploadCv.downloadUrl; } } };
CORS错误修复
登录DigitalOcean控制台,进入对应Spaces存储桶的设置页面,找到CORS配置项,添加如下规则:
- 允许的Origin:开发环境填
http://localhost:3000,生产环境填线上前端域名 - 允许的Method:勾选
PUT - 允许的Header:填
* - 暴露的Header:可留空
- 缓存时间:填300即可
保存配置后等待1-2分钟生效。
权限校验
确认你使用的DigitalOcean Spaces密钥对拥有该存储桶的s3:PutObject和s3:PutObjectAcl权限,避免权限不足导致的403错误。
内容的提问来源于stack exchange,提问作者Dawid Szemborowski
相关产品推荐
相关产品推荐

