Проблемы с перенаправлением на подписанный URL-адрес облачного хранилища (cURL?)

Я создаю HTTP-функцию Firebase, которая загружает файл в облачное хранилище, создает подписанный 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"

Если я попытаюсь вручную сделать запрос GET к URL-адресу в Postman, я получаю эквивалентную ошибку:

<?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 следует за перенаправлением или при создании запроса GET в Postman, что приводит к этой разнице в подписи?

2 ответа

Решение

Ответ Джосса Барона помог мне в правильном направлении, но это неправда, что это должно быть application/octet-stream. Это используется только для создания подписанного URL-адреса, который можно использовать для загрузки файла. В моем случае при создании подписанного URL-адреса с помощью Cloud Storage SDK для узла я не указывал a, поэтому при отправке GET запрос на подписанный URL, он не должен содержать Content-Type заголовок.

Если я правильно понял, проблема возникает в двух сценариях

  1. При прохождении CF через завиток с
       curl -L -H "Content-Type: application/json" "https://us-central1-example.cloudfunctions.net/exampleFunction" -d '{"example": true}')

Согласно примеру в github в документации Подписанный 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.

Если я попытаюсь вручную сделать запрос GET к URL-адресу в Postman, я получаю эквивалентную ошибку: я пробовал простой GET в почтальоне с использованием подписанного URL-адреса, и он работал нормально

Команда, используемая в gsutil для получения подписанного URL:

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

Затем я попробовал GET на почтальоне и работал нормально.

Я также попытался использовать подписанный URL-адрес для загрузки файла в Postman и работал нормально.

Я думаю, что в соответствии с общими типами MIME

application/octet-stream - значение по умолчанию для всех остальных случаев (не для текстовых файлов).

Когда вы устанавливаете тип контента как application/json, вы указываете формат JSON, но не объект или файл. Вот почему он работает со следующим, поскольку вы не указываете заголовок content-type, по умолчанию используется application/octet-stream

       curl -L "https://us-central1-example.cloudfunctions.net/exampleFunction" -d "example=true"
Другие вопросы по тегам