Облачное хранилище Google: настройки CORS не работают для подписанных URL-адресов

#google-cloud-platform #google-cloud-storage

# #google-облачная платформа #google-облачное хранилище

Вопрос:

Ответ PUT на запрос с подписанным URL — адресом не содержит заголовка Access-Control-Allow-Origin .

 import os
from datetime import timedelta

import requests
from google.cloud import storage

os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = <path to google credentials>
client = storage.Client()
bucket = client.get_bucket('my_bucket')
policies = [
    {
        'origin': ['*'],
        'method': ['PUT'],
    }
]
bucket.cors = policies
bucket.update()
blob = bucket.blob('new_file')
url = blob.generate_signed_url(timedelta(days=30), method='PUT')
response = requests.put(url, data='some data')

for header in response.headers.keys():
    print(header)
 

Выходной сигнал:

 X-GUploader-UploadID
ETag
x-goog-generation
x-goog-metageneration
x-goog-hash
x-goog-stored-content-length
x-goog-stored-content-encoding
Vary
Content-Length
Date
Server
Content-Type
Alt-Svc
 

Как вы можете видеть, CORS-заголовков нет. Итак, могу ли я сделать вывод, что GCS не поддерживает CORS должным образом / полностью?

Ответ №1:

Совместное использование ресурсов из разных источников (CORS) позволяет взаимодействовать между ресурсами из разных источников. По умолчанию в облачном хранилище Google это запрещено / отключено для предотвращения вредоносного поведения.

Вы можете включить его с помощью облачных библиотек, Rest API или Cloud SDK, соблюдая следующие правила:

  1. Аутентификация с использованием учетной записи пользователя / службы с разрешениями для типа облачного хранилища : FULL_CONTROL .
  2. Использование XML API для получения правильных заголовков CORS используйте один из двух URL-адресов:
 - storage.googleapis.com/[BUCKET_NAME]
- [BUCKET_NAME].storage.googleapis.com
 

Origin storage.cloud.google.com/[BUCKET_NAME] не будет отвечать заголовком CORS.

  1. Для запроса требуется правильный заголовок источника, соответствующий конфигурации источника политики корзины, как указано в пункте 3 документации по устранению неполадок CORS, в случае вашего кода:
 headers = {
    'ORIGIN': '*'
}
response = requests.put(url, data='some data', headers=headers)

for header in response.headers.keys():
    print(header)
 

выдает следующий вывод:

 X-GUploader-UploadID
ETag
x-goog-generation
x-goog-metageneration
x-goog-hash
x-goog-stored-content-length
x-goog-stored-content-encoding
Access-Control-Allow-Origin
Access-Control-Expose-Headers
Content-Length
Date
Server
Content-Type
 

Комментарии:

1. Это работает только для запросов GET. Но не работает для PUT. Посмотрите на предоставленный мной код. Я делаю то же самое, что вы предложили, за исключением метода PUT.

2. КСТАТИ, УДАЛЕНИЕ, которое вы использовали в политике корзины в вашем примере, также не работает.

3. В документации указано , что запрос предварительно отображается в любом другом методе, кроме: GET, HEAD или POST. Это включает в себя: ОПУБЛИКОВАТЬ и удалить. Вы пытались это проверить?

4. Да. Ответ на предполетный запрос не содержит заголовков CORS. В моем случае он УСТАНОВЛЕН (также установлен флажок УДАЛИТЬ).

5. Я воспроизвел вашу проблему и соответствующим образом обновил ответ. Это работает для меня.

Ответ №2:

У меня была эта проблема. Для меня проблема заключалась в том, что я использовал POST вместо PUT . Кроме того, мне пришлось настроить Content-Type тип загрузки в соответствии с типом содержимого, используемым для создания формы. Тип содержимого по умолчанию в демо-версии — «application / octet-stream», поэтому мне пришлось изменить его на тот, который был типом содержимого при загрузке. При выполнении XMLHttpRequest мне просто нужно было отправить файл напрямую, а не использовать FormData.

Так я получил подписанный URL-адрес.

     const options = {
        version: 'v4',
        action: 'write',
        expires: Date.now()   15 * 60 * 1000, // 15 minutes
        contentType: 'application/octet-stream',
    };

    // Get a v4 signed URL for uploading file
    const [url] = await storage
        .bucket("lsa-storage")
        .file(upload.id)
        .getSignedUrl(options as any);