Реализация возобновляемой загрузки больших файлов (chunked upload) позволяет передавать данные в сегментах, что снижает нагрузку на сеть и сервер, а также повышает отказоустойчивость процесса. Если соединение прерывается, клиент может перезапустить загрузку с того места, где она остановилась, вместо повторной отправки всего файла.

1. Подготовка файла на стороне клиента

Прежде чем начать передачу, файл нужно разбить на части заданного размера (обычно от 500 КБ до 10 МБ). Размер чанка зависит от скорости соединения и стабильности сети: для нестабильных каналов лучше использовать меньшие сегменты.

Используйте стандартный API чтения файлов в браузере или среде выполнения. Чтение файла построчно или буферизованным способом позволяет избежать загрузки всего объема в память сразу.

Пример логики на JavaScript: создайте цикл, который читает файл по размеру chunkSize и формирует массив байтов для каждого сегмента.

2. Настройка HTTP-заголовков и параметров запроса

Каждый чанк отправляется отдельным HTTP-запросом. В заголовке Content-Type укажите тип данных (например, multipart/form-data или application/octet-stream).

В заголовке Content-Length передайте размер текущего сегмента. Это позволяет серверу корректно обработать входящий поток.

Используйте заголовок X-File-ID или аналогичный уникальный идентификатор для каждого файла, чтобы сервер мог различать разные загрузки и собирать их по правильному файлу.

В заголовке Content-Disposition можно указать имя файла и его полный размер (например, filename="report.pdf", size="10485760"), чтобы сервер знал ожидаемый итоговый объем.

3. Обработка ответа сервера и прогресс-бар

Сервер должен возвращать HTTP-статус 200 (OK) или 206 (Partial Content) для каждого успешно принятого чанка.

Если сервер возвращает ошибку (например, 413 Too Request Entity Too Large), клиенту нужно обработать исключение и предложить пользователю изменить размер чанка или проверить соединение.

Для отображения прогресса используйте событие загрузки данных. Суммируйте количество успешно переданных байтов и делите на общий размер файла для вычисления процента выполнения.

Важно: если сервер возвращает ошибку, не отправляйте следующий чанк до тех пор, пока текущий не будет обработан или отменен.

4. Логика возобновления загрузки (Resume)

При повторном запуске клиент должен сообщить серверу, с какого чанка продолжить. Это делается через заголовок Range: bytes=start-end или специальный параметр в теле запроса.

Сервер должен поддерживать механизм проверки целостности данных. Используйте хеш-сумму (MD5, SHA-256) для каждого чанка или всего файла. При возобновлении клиент отправляет хеши уже переданных частей.

Если сервер подтверждает, что все части до определенной точки приняты корректно, загрузка продолжается с следующего сегмента.

В случае полной потери данных (например, удаление файла на сервере) процесс начинается заново. Клиент должен уметь определять, нужно ли начинать с нуля или продолжить.

5. Сборка файла на сервере

Сервер хранит каждый чанк в отдельном временном файле или базе данных. Используйте уникальные имена файлов, основанные на X-File-ID и номере сегмента.

После завершения загрузки (когда все части получены) сервер собирает их в один файл в указанной директории.

Проверьте целостность собранного файла, сравнив итоговый хеш с ожидаемым значением. Если они совпадают — файл готов к использованию.

Очистите временные файлы после успешной сборки или установите таймаут для удаления старых сегментов.

6. Ограничения и рекомендации

Не превышайте лимиты памяти сервера при хранении временных файлов. Убедитесь, что диск имеет достаточное пространство.

Учитывайте время жизни сессии на сервере. Если файл не собран в течение определенного времени, сегменты могут быть удалены автоматически.

Для очень больших файлов (сотни ГБ) рассмотрите использование распределенных систем хранения или специализированных протоколов вроде HTTP Range Requests с поддержкой multipart.

Всегда информируйте пользователя о статусе загрузки: «загружено 45%», «ошибка соединения, повторная попытка» и т.д.

Вопросы и ответы

Что делать, если сервер не поддерживает возобновление загрузки?

Если сервер не поддерживает Range-запросы или проверку хешей, клиенту придется отправлять весь файл заново при каждом прерывании. В этом случае рекомендуется настроить кэширование на стороне клиента или использовать более надежный канал связи.

Как выбрать оптимальный размер чанка?

Размер чанка зависит от скорости сети и стабильности соединения. Для мобильных сетей лучше использовать 1–5 МБ, для проводных — до 10–20 МБ. Проведите тесты с разными значениями и выберите тот, который обеспечивает минимальное время загрузки при максимальной устойчивости.

Можно ли использовать возобновляемую загрузку для видеофайлов?

Да, но с оговорками. Видеофайлы часто требуют потоковой передачи, а не полной загрузки. В таких случаях лучше использовать протоколы вроде HLS или DASH, которые изначально поддерживают сегментированную передачу.

По теме