重定向到签名的云存储URLcURL?的问题

问题描述

我正在创建一个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请求时,会导致签名上的差异吗?

解决方法

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

  1. 使用卷曲的方式击打CF时
curl -L -H "Content-Type: application/json" "https://us-central1-example.cloudfunctions.net/exampleFunction" -d '{"example": true}')

根据文档example in github中的Signed URL v4,应使用'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请求,则会收到一个等效的错误: 我在邮递员中使用签名URL尝试了一个简单的GET,效果很好

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

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

然后我尝试对邮递员进行GET操作,效果很好。 enter image description here

我还尝试使用签名URL在Postman中上传文件,并且效果很好。

根据Common MIME types

,我的想法是

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

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

curl -L "https://us-central1-example.cloudfunctions.net/exampleFunction" -d "example=true"
,

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