Scaleway S3兼容对象存储预签名URL分片上传预检请求403问题
问题根因
这是Scaleway对象存储S3兼容层的实现不符合AWS规范导致的:
AWS原生S3处理CORS预检OPTIONS请求时,会完全忽略请求中的签名相关参数,直接根据Bucket的CORS配置返回响应,不会做签名校验。但Scaleway当前的实现会对所有请求(包括OPTIONS预检)都执行签名校验,而你生成的预签名URL是针对PUT方法的,浏览器自动发起的OPTIONS请求方法和签名时的方法不匹配,自然会返回403 AccessDenied错误。你移除查询参数后预检成功,就是因为没有了签名参数,Scaleway的校验逻辑走了纯CORS配置匹配的分支。
可行解决方案
方案1:新增后端代理层
所有对象存储的跨域请求都先走你自己的后端服务:- 后端收到OPTIONS预检请求时,直接返回符合要求的CORS响应头,不需要转发到Scaleway
- 收到实际的PUT分片上传请求时,再把请求转发到Scaleway的预签名地址,或者后端直接用密钥签名后上传
这个方案兼容性最好,不需要依赖云厂商的修复,也不会额外增加前端复杂度。
方案2:使用表单上传替代预签名PUT上传
把分片上传的逻辑改成POST表单上传的方式,生成预签名的POST policy,前端用FormData携带分片数据提交,这种方式可以避免触发复杂的预检校验,适配Scaleway的现有实现。方案3:调整配置尝试兼容(部分场景可用)
如果你暂时不想加代理,可以尝试做以下调整:- 调整S3客户端初始化配置,强制使用V4版本签名:
const S3Client = new S3({ credentials: { accessKeyId: env.SCW_ACCESS_KEY, secretAccessKey: env.SCW_SECRET_KEY, }, endpoint: `https://s3.${env.SCW_REGION}.scw.cloud`, signatureVersion: 'v4', // 强制使用v4版本签名 region: env.SCW_REGION, // 补充区域参数,签名生成时需要 })- 在Scaleway控制台调整Bucket的CORS规则:精确填写允许的Origin(不要用*通配符)、明确允许OPTIONS和PUT两种方法、允许的请求头明确添加
*。
注意该方案仅在部分Scaleway区域可用,不保证全场景生效。
内容的提问来源于stack exchange,提问作者Antoine Laffargue
相关产品推荐
相关产品推荐

