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

React-Django使用签名URL上传GCS报403 SignatureDoesNotMatch错误求助

解决Google Cloud Storage签名URL上传时的SignatureDoesNotMatch错误

问题概述

生成签名URL用于客户端直接上传最大1GB的MP3/视频文件至Google Cloud Storage,但上传时触发以下错误:

return (<Code> SignatureDoesNotMatch </Code> <Message> Access denied. </Message> <Details> The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method. </Details>
)

生成的URL格式示例:

https://storage.googleapis.com/bucket-name/filename?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=something.iam.gserviceaccount.com%2xyz%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20240207T120631Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature=21...

前端React上传代码

const responseForSignedUrl = await axios.get(`${baseUrl}/api/posts/getuploadurl/`);
if (responseForSignedUrl.status !== 200) {
  throw new Error("Failed to obtain signed URL.");
}

const signedUrl = responseForSignedUrl.data.url;

// Upload video file to Cloud Storage using the signed URL
const videoFormData = new FormData();
videoFormData.append("file", video_file);

const uploadResponse = await axios.put(signedUrl, videoFormData, {
  headers: {
    "Content-Type": "video/mp4",
  },
  onUploadProgress: (progressEvent) => {
    const percentCompleted = Math.round(
      (progressEvent.loaded * 100) / progressEvent.total
    );
    setProgress(percentCompleted);
  },
});

if (!uploadResponse.ok) {
  throw new Error("Failed to upload video file.");
}

后端Django生成签名URL代码

def generate_upload_signed_url_v4(request):
    """Generates a v4 signed URL for uploading a blob using HTTP PUT.

    Note that this method requires a service account key file. You can not use
    this if you are using Application Default Credentials from Google Compute
    Engine or from the Google Cloud SDK.
    """
    bucket_name = 'production-bucket-name'
    blob_name = 'test1'

    # storage_client = storage.Client()
    current_directory = os.path.dirname(os.path.abspath(__file__))

    # Navigate to the parent directory (folder A)
    parent_directory = os.path.dirname(current_directory)

    # Access file B within folder A
    file_b_path = os.path.join(parent_directory, "service-credentials.json")
    storage_client = storage.Client.from_service_account_json(file_b_path)
    bucket = storage_client.bucket(bucket_name)
    blob = bucket.blob(blob_name)
    print(storage_client)
    url = blob.generate_signed_url(
        version="v4",
        # This URL is valid for 15 minutes
        expiration=datetime.timedelta(minutes=15),
        # Allow PUT requests using this URL.
        method="PUT",
        content_type="video/mp4",
       
    )


    return JsonResponse({'url': url})

已尝试操作

  • 创建拥有有效权限的新服务账户并获取密钥,问题仍存在
  • 更换Content-Type为application/octet-stream和multipart/form-data

核心问题与修复方案

问题根源在于前端上传方式错误:

  1. 不要使用FormData封装文件
    签名URL的PUT请求要求直接上传文件原始内容,而FormData会自动将请求的Content-Type修改为multipart/form-data; boundary=...,即使手动设置video/mp4也会被覆盖,导致签名验证时的Content-Type不匹配,触发SignatureDoesNotMatch错误。

  2. 直接上传文件对象
    去掉FormData封装,直接将文件对象作为PUT请求的主体。修改后的前端代码如下:

const responseForSignedUrl = await axios.get(`${baseUrl}/api/posts/getuploadurl/`);
if (responseForSignedUrl.status !== 200) {
  throw new Error("Failed to obtain signed URL.");
}

const signedUrl = responseForSignedUrl.data.url;

// 直接上传文件对象,无需FormData
const uploadResponse = await axios.put(signedUrl, video_file, {
  headers: {
    "Content-Type": "video/mp4", // 必须与签名URL生成时指定的content_type完全一致
  },
  onUploadProgress: (progressEvent) => {
    const percentCompleted = Math.round(
      (progressEvent.loaded * 100) / progressEvent.total
    );
    setProgress(percentCompleted);
  },
});

if (!uploadResponse.ok) {
  throw new Error("Failed to upload video file.");
}
  1. 额外注意事项
  • 确保生成签名URL时的content_type与上传请求头的Content-Type完全一致,包括大小写、附加参数(例如video/mp4; codecs="avc1.42E01E, mp4a.40.2"需完全匹配)
  • 针对1GB大文件,后续可考虑启用GCS分块上传,但需先解决当前签名不匹配问题
  • 再次确认服务账户拥有storage.objects.create权限,避免权限遗漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 08:25:07