Проблемы с перенаправлением на подписанный 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
заголовок.
Если я правильно понял, проблема возникает в двух сценариях
- При прохождении 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"