Загрузка больших файлов с докачкой: tusd на VPS для клиентского кабинета
Клиент отправляет видеозапись, полоса доходит до девяноста восьми процентов, и связь пропадает. После возвращения интернета сайт предлагает начать сначала. Формально ничего страшного: файл ведь не повреждён. Неформально человек уже придумал несколько названий для вашего интерфейса, и ни одно не годится для рекламного буклета.
Протокол tus решает конкретную задачу: продолжать передачу с позиции, которую сервер уже подтвердил. Его серверная реализация tusd подходит для личного кабинета, приёма исходников, документов и других крупных файлов. При этом загрузчик не заменяет пользователей, права доступа и учёт свободного места — эти обязанности остаются у вашего приложения.
Разберём устройство такой системы и локальную проверку докачки. Затем — что нужно добавить перед тем, как открыть её реальным клиентам.
Содержание
VPS для приёма клиентских файлов
Разместите tusd и своё приложение на отдельном сервере. Подберите диск по размеру файлов, числу одновременных загрузок и срокам хранения материалов.
Выбрать VPS для загрузки файловСервер помнит не проценты, а смещение
Обычная форма часто отправляет файл одним запросом. Если передача оборвалась, приложение не всегда знает, какой объём действительно сохранён. В tus клиент создаёт загрузку, получает её адрес, узнаёт подтверждённое смещение и отправляет следующую часть именно с этой позиции.
Для этого используются запросы POST, HEAD и PATCH, а состояние описывают специальные заголовки. Поведение определено в спецификации tus. Серверное смещение важнее клиентского счётчика: браузер мог отправить данные в сеть, но это ещё не означает, что сервер их принял.
Представим мастерскую, которой заказчики присылают исходники для монтажа. У загрузки есть собственный идентификатор, владелец, связанный заказ, ожидаемый размер и состояние. Пока передача не завершена, монтажёр не видит файл как готовый материал. После завершения система проверяет содержимое и только затем включает его в заказ.
Такой жизненный цикл защищает от странного случая, когда файл появился в списке, но половина кадров ещё путешествует по интернету.
Отделите приём файлов от обработки
Удобная схема состоит из веб-приложения с пользователями, tusd для передачи и отдельного обработчика завершённых загрузок. Перед ними стоит HTTPS-прокси. Хранилищем может быть выделенный каталог или поддерживаемое объектное хранилище.
Основное приложение выдаёт разрешение на конкретную загрузку и связывает её с заказом. tusd принимает байты. Обработчик проверяет тип файла, вычисляет контрольную сумму, выполняет антивирусную проверку по требованиям проекта и создаёт превью. Тяжёлое перекодирование не должно задерживать подтверждение каждого переданного фрагмента.
Сразу определите состояния: создана, передаётся, получена, проверяется, готова, отклонена. Пользователь должен понимать разницу между «файл передан» и «материал принят». Это снижает количество обращений в поддержку лучше, чем бесконечно вращающийся индикатор без объяснения.
Не используйте присланное имя файла как путь на сервере. Храните безопасный внутренний идентификатор, а исходное имя — как отображаемые данные после проверки. Два заказчика вполне могут одновременно отправить final_final_2.mp4; серверу не следует выбирать любимчика.
Проверим докачку на маленьком файле
Установите официальный выпуск tusd под архитектуру своего VPS и подготовьте каталог с правами сервисного пользователя. Для опыта запустите процесс только на локальном адресе:
tusd -host 127.0.0.1 -port 1080 \
-upload-dir /srv/tusd-test \
-max-size 10000000000 -disable-download
Каталог /srv/tusd-test должен существовать и быть доступен этому пользователю. Лимит в примере равен десяти миллиардам байтов на файл. Это учебный локальный запуск без пользовательской авторизации; его нельзя просто опубликовать наружу. Значение флагов приведено в руководстве tusd.
Создадим загрузку длиной шесть байтов. Большой файл проверим позже: для понимания протокола достаточно abcdef.
curl -i -X POST http://127.0.0.1:1080/files/ \
-H 'Tus-Resumable: 1.0.0' \
-H 'Upload-Length: 6' \
-H 'Content-Length: 0'
Из ответа возьмите адрес в заголовке Location. В следующих командах UPLOAD_URL означает переменную с этим фактическим адресом; не подставляйте адрес чужой загрузки.
curl -i -X PATCH "$UPLOAD_URL" \
-H 'Tus-Resumable: 1.0.0' \
-H 'Upload-Offset: 0' \
-H 'Content-Type: application/offset+octet-stream' \
--data-binary 'abc'
curl -I "$UPLOAD_URL" -H 'Tus-Resumable: 1.0.0'
После успешной первой части сервер должен сообщить смещение 3. Это и есть точка продолжения. В новой сессии клиента запросите состояние ещё раз, затем отправьте остаток:
curl -i -X PATCH "$UPLOAD_URL" \
-H 'Tus-Resumable: 1.0.0' \
-H 'Upload-Offset: 3' \
-H 'Content-Type: application/offset+octet-stream' \
--data-binary 'def'
Убедитесь, что итоговый размер равен шести байтам и сервер сохранил abcdef. Если указать неверное смещение, корректная реализация не должна молча дописать данные в случайное место. Такой отрицательный опыт тоже включите в приёмку.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
АРЕНДОВАТЬ СЕРВЕРПочему прокси способен испортить правильную докачку
Когда локальный опыт работает, подключайте HTTPS-прокси. Для tusd за прокси используется -behind-proxy, а прокси должен передавать исходное имя хоста и протокол. Проверьте заголовок Location: браузер должен получать доступный HTTPS-адрес, а не внутренний порт сервера.
В Nginx важно отключить буферизацию тела запроса для маршрута загрузки через proxy_request_buffering off. Иначе посредник может сначала целиком принять запрос, прежде чем отправить его tusd. Лимит тела запроса и тайм-ауты также согласуют с размером фрагментов и ожидаемой скоростью клиента.
Проверяйте весь путь, включая CDN, защитный шлюз и балансировщик, если они есть. Один промежуточный узел с небольшим лимитом способен отклонять фрагменты, хотя оба крайних сервера настроены правильно. Начните с небольших частей, затем подберите размер по измерениям и ограничениям инфраструктуры.
Если интерфейс и загрузчик находятся на разных доменах, браузеру потребуются корректные правила CORS и доступ к служебным заголовкам. CORS не является авторизацией: его отсутствие не мешает постороннему клиенту вне браузера отправлять запросы.
Пользовательские права нельзя заменить длинной ссылкой
Перед созданием загрузки приложение проверяет пользователя, заказ, разрешённый размер и остаток квоты. Для продолжения и удаления также нужна проверка владельца. Доступ к HEAD не должен раскрывать чужие метаданные, а доступ к PATCH — позволять дописывать чужой файл.
В tusd есть механизм hooks, через который приложение получает события и может отклонять создание загрузки. Но проверка pre-create сама по себе не защищает все последующие запросы. Авторизацию каждого требуемого действия организуйте в приложении или шлюзе, связав разрешение с конкретным идентификатором загрузки.
Не выдавайте бессрочный универсальный токен «на любые файлы». Ограничьте его область и время действия, предусмотрите безопасное обновление во время долгой передачи. Пользователь не должен терять уже отправленные гигабайты только потому, что короткая сессия истекла на последней минуте.
По умолчанию tusd умеет отдавать загруженные файлы по GET. В закрытом клиентском кабинете используйте -disable-download и отдельную выдачу после проверки доступа. Ссылка на загрузку и разрешение скачать готовый документ — разные вещи.
События завершения обрабатывайте идемпотентно. Повторная доставка уведомления не должна дважды создавать материал в заказе. А тяжёлую проверку запускайте через очередь, сохранив статус и понятный результат для пользователя.
Полученный файл сначала попадает в закрытую область проверки. Не разрешайте запуск загруженных файлов как серверных скриптов и не определяйте их содержимое только по расширению. Для архивов ограничьте суммарный размер распаковки и число элементов: небольшой входящий файл способен превратиться в очень большой набор данных. Отклонённую загрузку отмечайте отдельно, с причиной и порядком освобождения занятого места.
Браузер тоже должен уметь продолжать
Для интерфейса используйте совместимый клиент, например tus-js-client. Он предоставляет средства загрузки, повторов и поиска предыдущих передач. Встройте их в собственный интерфейс с отменой, отображением прогресса и понятным сообщением при потере сети.
После перезагрузки страницы браузер не всегда может незаметно снова прочитать локальный файл. Может потребоваться повторный выбор пользователем того же файла. Объясните это честно: «Выберите исходный файл, чтобы продолжить», а не «Всё пропало, загрузите заново».
Проверьте несколько случаев: краткое отключение Wi-Fi, закрытие вкладки, перезапуск сервиса, истечение токена и попытку продолжить другой файл под прежним идентификатором. После каждого успешного завершения сравните контрольную сумму исходника и результата. Сто процентов на индикаторе не заменяют проверку целостности.
Рассчитайте место для незавершённых попыток
Диск занят не только готовыми материалами. На нём остаются прерванные передачи, временные результаты проверки и превью. Для примера: десять одновременно начатых загрузок по 8 ГБ могут потребовать до 80 ГБ ещё до обработки. Это арифметика планирования, а не гарантия пропускной способности сервера.
Установите срок хранения незавершённых загрузок и процедуру очистки, которая учитывает активные передачи и выбранный backend. Освобождение места должно возвращать квоту владельцу. Нельзя просто удалять все старые файлы по дате, не проверяя их состояние.
Для пилотного приёма файлов в MAATRIX можно рассмотреть Uab Start с 2 vCPU и 4 ГБ памяти, но его диск 80 ГБ быстро становится ограничением. Heka Standard даёт 160 ГБ, Maat Pro — 240 ГБ; необходимый объём считайте по своим файлам и срокам хранения. Перекодирование видео оценивайте отдельно от самой загрузки.
Обычный VPS подходит для запуска приложения и tusd с самостоятельной настройкой. Когда архив растёт, разумно отделить постоянное хранение от вычислений. Тогда загрузчик занимается своей задачей: спокойно принимает файл, переживает разрыв связи и передаёт приложению проверяемый результат.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
АРЕНДОВАТЬ СЕРВЕРОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →