Вопрос или проблема
Я хочу, чтобы пользователи загружали огромные файлы непосредственно в Azure Storage. У меня есть веб-приложение на Flask Python, но я не хочу, чтобы файл загружался на мой веб-сервер из-за ограничений по размеру.
Когда пользователь выбирает файл для загрузки и нажимает кнопку загрузки, происходит следующее:
- Вызывается API, который генерирует URL SAS и имя блоба для файла, который нужно загрузить. Код, генерирующий оба значения:
blob_name = str(uuid.uuid4())
container_name = os.environ[default_container_name_setting]
sas = generate_blob_sas(account_name=service.account_name,
account_key=access_key,
container_name=container_name,
blob_name=blob_name,
permission=BlobSasPermissions(write=True, read=True, create=True),
expiry=datetime.utcnow() + timedelta(hours=2))
sas_url="https://" + service.account_name + '.blob.core.windows.net/' + container_name + "https://stackoverflow.com/" + blob_name + '?' + sas
return sas_url, blob_name
- Файл затем загружается по частям:
const chunkSize = 1024 * 1024 * 20;
const totalChunks = Math.ceil(file.size / chunkSize);
const blockIds = []; // Массив для хранения идентификаторов блоков
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
const blockId = btoa("block-" + i); // Кодирование идентификатора блока в base64
blockIds.push(blockId);
// Загрузка каждой части
const uploadResponse = await fetch(sas_url + "&comp=block&blockid=" + blockId, {
method: "PUT",
headers: {
"x-ms-blob-type": "BlockBlob",
"Content-Type": file.type
},
body: chunk
});
if (!uploadResponse.ok) {
return false;
}
}
На этом этапе всё работает. Однако следующий шаг — сказать Azure соединить части:
const commitResponse = await fetch(sas_url + "&comp=commitBlockList", {
method: "PUT",
headers: {
"Content-Type": "application/xml",
"x-ms-version": "2020-10-02",
"Content-Length": "0"
},
body: `<BlockList>${blockIds.map(id => `<Latest>${id}</Latest>`).join('')}</BlockList>`
});
if (!commitResponse.ok) {
throw new Error("Не удалось подтвердить блоки блоба.");
}
В этот момент у меня всегда возникает ошибка CORS:
Доступ к fetch по адресу ‘https://xxx.blob.core.windows.net/container/e07d13fa-bcd6-45cf-9eea-3295e17dc567?se=2024-11-01T04%2A18%3B30Q&sp=rcw&sv=2024-11-04&sr=b&sig=CudrFGsJ1HGnYo6Bh3K7WVAabgdOAsPteWq47XKuKDI%3D&comp=commitBlockList’ из источника ‘http://localhost:4449’ заблокирован политикой CORS: Ответ на предварительный запрос не проходит проверку контроля доступа: В заголовке ‘Access-Control-Allow-Origin’ нет разрешенного ресурса. Если прозрачный ответ соответствует вашим потребностям, установите режим запроса на ‘no-cors’, чтобы получить ресурс с отключенным CORS.
Я знаю, что правильно настроил CORS в Azure Storage, потому что часть загрузки работает.
На вкладке Blob Service я добавил свой localhost-источник с разрешенными методами GET, POST, OPTIONS и PUT.
Я пробовал снова сгенерировать URL SAS с полученным именем Blob, но я всё еще получаю ошибку CORS.
Что я упускаю?
Ответ или решение
Ошибка CORS при вызовах Azure Storage из JavaScript для завершения загрузок чанками
Когда вы работаете с загрузками файлов в Azure Storage через JavaScript, особенно с использованием ссылок SAS (Shared Access Signature), вы можете столкнуться с ошибкой CORS (Cross-Origin Resource Sharing). Эта ошибка возникает, когда браузер блокирует запрос к ресурсу с другого домена из-за политик безопасности. Давайте подробно разберем вашу ситуацию и предложим возможные решения.
Описание проблемы
Вы реализуете upload больших файлов в Azure Storage без передачи данных через свой Flask-сервер. Совершенно логично, что такой подход позволяет избежать проблем с исчерпанием ресурсов сервера. Ваш текущий процесс загружает файл в чанках, а затем вызывает метод commitBlockList
для объединения загруженных чанков. Однако на этапе вызова commitBlockList
вы получаете ошибку CORS:
Access to fetch at 'https://xxx.blob.core.windows.net/...' from origin 'http://localhost:4449' has been blocked by CORS policy.
Настройка CORS в Azure Storage
Вы упомянули, что правильно настроили CORS в Azure Storage, добавив свой localhost в список разрешенных источников с методами GET, POST, OPTIONS и PUT. Это правильный подход, но убедитесь, что все настройки CORS действительно применены. Важные моменты, которые стоит проверить:
-
Убедитесь в корректности домена: Проверьте, что вы используете точно такое же значение для домена в настройках CORS. Иногда лишние символы или пробелы могут вызвать проблемы.
-
Правильность методов: Убедитесь, что вы добавили метод OPTIONS в список разрешенных методов. Хотя это часто делается автоматически, иногда дополнительные настройки могут не сохраняться.
-
Параметры заголовков: Проверьте настройки заголовков. Часто полезно разрешить заголовки
Content-Type
иx-ms-blob-type
, чтобы избежать проблем с запросами, используя дополнительные параметры.
Диагностика и отладка
Для отладки ошибок CORS выполните следующие шаги:
-
Проверьте ответы на предзапросы: Используйте инструменты разработчика в вашем браузере, чтобы проанализировать сетевые запросы. Убедитесь, что запросы OPTIONS выполняются успешно, и Azure отвечает с правильными заголовками CORS.
-
Сравните разные методы запроса: Проверьте, как CORS обрабатывается при вызове PUT на этапе загрузки чанков и при вызове
commitBlockList
. Если предзапрос дляcommitBlockList
возвращает ошибку, это и вызывает основную проблему. -
Тестируйте на других доменах: Если возможно, протестируйте код на другом домене, чтобы понять, является ли проблема специфичной для localhost.
Альтернативные подходы
Если все вышеперечисленные шаги не решают проблему, рассмотрите возможность использования другого клиентского подхода:
-
Согласно подходу
no-cors
: Возможно, вам стоит установить режим запроса вno-cors
, но будьте осторожны: в этом режиме браузер не возвращает данные о статусе ответа. Это может быть полезно только для тестирования, и не рекомендуется для выполнения окончательных бизнес-логик. -
Использование Azure Functions: Рассмотрите возможность использования Azure Functions для обработки запросов. Функции могут служить промежуточным звеном между вашим клиентом и Azure Storage, управляя CORS настройками более гибко.
-
Серверный подход: Если всё ещё возникают сложности, возможно, стоит временно переключиться на загрузку через сервер, чтобы проверить, действительно ли проблема в CORS.
Заключение
Ошибка CORS при работе с Azure Storage может быть вызвана рядом факторов, включая неверную настройку на стороне Azure и характеристики самого запроса. Проведите тщательную проверку всех настроек и используйте подходы для диагностики. Наконец, допускайте возможность использования промежуточных решений, пока не будет принято окончательное решение.
Постоянный анализ и улучшения в вашем процессе загрузки помогут избежать подобных ситуаций в будущем и сделают ваш проект более устойчивым и удобным для пользователей.