You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 19:24:05