1

我正在创建一个 Firebase HTTP 函数,该函数将文件上传到 Cloud Storage,为该文件创建一个签名 URL,然后将客户端重定向到该 URL。使用 Postman 并打开自动重定向跟踪,可以正确检索文件。但是,如果我在使用 cURL ( ) 时尝试打开重定向curl -L -H "Content-Type: application/json" "https://us-central1-example.cloudfunctions.net/exampleFunction" -d '{"example": true}',Cloud Storage 会返回以下错误:

<?xml version='1.0' encoding='UTF-8'?>
<Error>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message>
    <StringToSign>GET

application/json
1602245678
/example.appspot.com/exampleBucket/exampleFile.txt</StringToSign>
</Error>

如果我使用表单编码数据发出请求,它也可以在 cURL 中使用:curl -L "https://us-central1-example.cloudfunctions.net/exampleFunction" -d "example=true"

如果我尝试手动向 Postman 中的 URL 发出 GET 请求,则会收到等效错误:

<?xml version='1.0' encoding='UTF-8'?>
<Error>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message>
    <StringToSign>GET


1602246219
/www.google.com/example.appspot.com/exampleBucket/exampleFile.txt</StringToSign>
</Error>

如果我将 URL 粘贴到浏览器中或使用 cURL 下载签名的 URL,则文件也会正确下载。

我正在使用以下函数来获取签名的 url:

async getSignedUrl(file: File, expireAt: number): Promise<string> {
    const [url] = await file
        .getSignedUrl({
            action: "read",
            expires: expireAt
        });

    return url
}

它返回以下格式的签名 URL:( https://storage.googleapis.com/example.appspot.com/exampleBucket/exampleFile.txt?GoogleAccessId=[Access ID]&Expires=1602246219&Signature=[Signature]我注意到“Expires”的值与标签中返回的值相同)。

我怀疑 Postman 和 cURL 在请求中添加了一些内容,导致签名不同,但我不确定到底发生了什么。

当让 cURL 跟随重定向或在 Postman 中创建 GET 请求时会发生什么,这会导致签名的这种差异?

4

2 回答 2

1

如果我理解正确,问题出现在两种情况下

  1. 当通过 curl 击中你的 CF 时
curl -L -H "Content-Type: application/json" "https://us-central1-example.cloudfunctions.net/exampleFunction" -d '{"example": true}')

根据文档Signed URL v4中 github 中的示例,应使用:'Content-Type: application/octet-stream'

curl -X PUT -H 'Content-Type: application/octet-stream' --upload-file my-file '${url}'

我尝试了以下成功的结果:

curl -X PUT -H 'Content-Type: application/octet-stream' -d '{"example": true}' 'https://storage.googleapis.com/...'

如果我尝试与content-type您共享的结果失败。

2.

如果我尝试手动向 Postman 中的 URL 发出 GET 请求,我会得到一个等效的错误:我在 postman 中使用签名 URL 尝试了一个简单的 GET,它工作得很好

gsutil 中用于获取签名 URL 的命令:

 gsutil signurl -d 10m key.json gs://BUCKET/aa.png

然后我在邮递员上尝试了一个 GET 并且工作得很好。 在此处输入图像描述

我还尝试使用签名 URL 在 Postman 中上传文件并且工作得很好。

我的想法是,根据常见的 MIME 类型

application/octet-stream 是所有其他情况(不是文本文件)的默认值。

当您将内容类型设置为 application/json 时,您指定的是 JSON 格式,而不是对象或文件。这就是它与以下内容一起使用的原因,因为您没有指定 header content-type,所以采用默认值application/octet-stream

curl -L "https://us-central1-example.cloudfunctions.net/exampleFunction" -d "example=true"
于 2020-10-13T17:16:24.967 回答
0

Joss BaronsContent-Type的回答帮助我朝着正确的方向前进,但必须如此并非如此application/octet-stream。这仅用于创建可用于上传文件的签名 url。就我而言,在使用 Cloud Storage SDK for node 创建签名的 url 时,我没有指定 a Content-Type,因此在向签名的 url 发送GET请求时,它不能包含Content-Type标头。

于 2021-02-15T13:30:43.283 回答