(React-Django)使用签名网址将文件上传到谷歌云存储时出现 403 Forbidden

问题描述 投票:0回答:1

我创建了签名 URL,用于从客户端直接将文件(最大 1GB 的 mp3 视频文件)上传到云存储上。但是当我尝试上传文件时,出现以下错误:

<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...

前端处于反应状态,我首先调用以获取signedurl,然后上传文件。 反应代码:


      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.");
      }

生成签名 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})
  • 尝试创建一个具有有效权限的新服务帐户,然后获取密钥,但没有成功。所以很确定代码有问题。
  • 尝试使用 application/octet-stream 和 multipart/form-data 更改内容类型 我是否在请求标头中遗漏了某些内容?
python reactjs django google-cloud-storage signed-url
1个回答
0
投票

我发现了这个错误。使用 FormData() 形成请求将始终发送内容类型为“multipart/form-data”的请求。因此,即使我们使用任何其他内容类型创建签名 url,它也会失败。我不知道为什么当我在签名网址时使用表单数据时它也失败了。无论如何,我们只需要发送文件,只是视频文件,同时发送请求而不是表格。

© www.soinside.com 2019 - 2024. All rights reserved.