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

Django-React下Google Cloud Storage签名URL上传失败问题

GCS签名URL跨栈上传失败排查修复

核心问题汇总

  • 前端请求方法与签名约定不匹配:GCS单文件PUT类型签名URL要求使用PUT方法发起请求,现有React代码错误使用POST方法
  • 前端携带非法请求头:Access-Control-Allow-Origin、Access-Control-Allow-Methods是服务端CORS响应的专属头,前端请求时携带这类未纳入签名计算范围的头,会直接触发签名校验失败
  • 上传数据格式错误:PUT方式上传不需要将文件包装为FormData对象,FormData会自动添加分隔符、内容描述等额外字节,与签名时约定的请求体内容不一致
  • 签名URL转义错误:贴出的curl命令、CreateAssets接口地址中,参数分隔符&被错误转义为HTML实体&,会导致参数解析异常
  • CORS配置桶不匹配:执行CORS配置命令时指定的桶是production-my-storage,实际上传使用的桶是production-videoo-storage,CORS规则未生效到目标桶
  • 签名本身校验失败:排除前端问题后裸curl测试仍返回签名不匹配,说明后端签名生成逻辑存在问题

分步修复方案

1. 先修复后端签名生成逻辑

从curl返回的StringToSign内容看,签名的基础结构(PUT方法、无额外Content-MD5、无自定义头、过期时间、对象路径)是符合规范的,优先排查以下问题:

  • 确认签名使用的服务账号私钥与GoogleAccessId参数对应的账号videoo-348016@appspot.gserviceaccount.com完全匹配,私钥内容无转义、缺漏
  • 生成签名URL后禁止做HTML实体转义,返回给前端的URL必须是原始格式,参数用原生&分隔,不能出现&
  • 签名时指定的HTTP方法、Content-Type必须和前端实际请求完全一致:如果签名时未指定Content-Type,前端请求时要么不携带Content-Type头,要么传入的值和签名时填写的值完全一致,不能随意填写video/mp4

2. 修正React端代码

删除多余逻辑,修正后的上传代码参考:

export const UploadVideo = async (file, signedurl, asset_uuid) => {
    let resultState = { state: '', data: {} };

    let config = {
        method: 'PUT', // 必须和签名约定的方法一致
        url: signedurl,
        headers: {
            // 仅保留签名时约定的Content-Type,未约定则删除该头
            'Content-Type': file.type
        },
        data: file, // 直接传入原始File对象,不要包装FormData
    };

    try {
        const response = await axios(config);
        console.log(JSON.stringify(response.data));
        resultState.state = 'success';
    } catch (error) {
        resultState.state = 'error';
        resultState.data.message = error.message;
        window.toastr.error(error.message);
        console.log(error)
    }

    return resultState;
}

export const CreateAssets = async (data, key) => {
    let resultState = { state: '', data: {} };
    // 把URL里的&全部替换为&,修正参数转义错误
    await axios.get(`https://origin/asset/create/?category=1&title="${data[key].title}"&size=1`)
        .then(res => {
            resultState.state = 'success';
            resultState.data = res.data;
        }).catch((err) => {
            resultState.state = 'error';
            resultState.data['message'] = err.message;
        })
    return resultState;
}

3. 重新配置目标桶CORS规则

现有CORS规则的内容已经满足上传需求,只需要给正确的目标桶重新执行配置命令即可:

gsutil cors set google-storage-cors.json gs://production-videoo-storage

4. 验证流程

  1. 先从后端拿到未转义的原始签名URL,用curl测试,注意URL里的参数分隔符必须是&,不能带&:
    curl -X PUT --upload-file /Users/utku/Desktop/cat.mp4 "替换为你的原始签名URL"
    
  2. curl返回200状态码、无错误信息,说明签名逻辑正常
  3. 再调用前端上传逻辑,即可正常完成上传

内容的提问来源于stack exchange,提问作者london_utku

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 17:45:38