Завантаження двогігабайтного відео через WiFi у кав'ярні — це справжній прояв оптимізму. Ви спостерігаєте, як смуга прогресу повільно повзе до сімдесяти відсотків, і раптом зв'язок зникає. Завантаження переривається. Коли ви намагаєтеся знову, сервер очікує абсолютно новий файл. Ви починаєте з нуля. Для кожного, хто розробляє додаток для роботи з відео, створеним користувачами, це не виняток. Це норма. Протокол tus був створений саме для того, щоб вирішити цю проблему. Це відкритий стандарт, який працює через звичайний HTTP і надає процесу завантаження «пам'ять». Коли мережа відновлюється, передача файлу продовжується саме з того місця, де вона зупинилася.

Чому стандартні завантаження перериваються

Стандартні багаточастинні (multipart) завантаження файлів розглядають усе корисне навантаження як одну транзакцію. Браузер або додаток відкриває TCP-з'єднання, передає байти потоком і очікує на 200 OK у кінці. Якщо з'єднання розривається через те, що користувач переключився з LTE на WiFi або ноутбук перейшов у режим сну, сервер не має можливості дізнатися, які саме байти надійшли успішно. Більшість фреймворків просто відкидають неповні дані. Користувач залишається з помилкою у формі та поганим настроєм. Відеофайли посилюють цю проблему, оскільки вони великі, часто завантажуються з мобільних пристроїв через нестабільні мережі та часто закодовані у форматах, які неможливо обробити, доки файл не буде завантажений повністю.

Як tus змінює правила гри

Tus переосмислює завантаження як stateful-діалог (з підтримкою стану), а не як одноразову доставку. Замість того, щоб надсилати файл одним безперервним потоком байтів, клієнт розбиває корисне навантаження на частини (chunks). Що ще важливіше, сервер запам'ятовує зміщення (offset) — точну кількість байтів, які він отримав на цей момент. Саме ця стійкість стану робить можливість відновлення завантаження реальною. Протокол навмисно простий. Він не потребує WebSockets, gRPC або пропрієтарних SDK. Він використовує методи HTTP, які ви вже знаєте.

Три запити, що забезпечують відновлення

Кожне завантаження через tus проходить за передбачуваним сценарієм.

По-перше, клієнт надсилає POST-запит на відому кінцеву точку tus. Заголовки описують файл. Заголовок Upload-Length вказує кінцевий розмір у байтах, а необов'язкові метадані, такі як ім'я файлу або тип вмісту, передаються в заголовку Upload-Metadata як список пар ключ-значення у форматі base64, розділених комами. Сервер створює порожній ресурс завантаження і відповідає статусом 201 Created, а також заголовком Location, що вказує на унікальний URL. Цей URL є адресою завантаження на весь наступний час.

Далі йде PATCH-запит. Клієнт надсилає частини (chunks) сирих бінарних даних на цей унікальний URL. Корисне навантаження супроводжують два критично важливі заголовки. Content-Type має бути application/offset+octet-stream, а Upload-Offset повинен відповідати позиції байта, з якої починається ця частина. Сервер перевіряє, чи збігається зміщення з його власними записами. Якщо ні, сервер повертає 409 Conflict, запобігаючи пошкодженню стану. Якщо все збігається, сервер додає байти, оновлює своє внутрішнє зміщення і повертає відповідь 204 No Content разом із новим Upload-Offset. Розмір частини можна налаштувати, але зазвичай він становить від кількох сотень кілобайт до кількох мегабайт. Менші частини створюють більше HTTP-навантаження, але швидше відновлюються після помилок. Більші частини зменшують кількість циклів запитів (round trips), але витрачають більше трафіку, якщо вони перериваються в процесі передачі.

Нарешті, HEAD-запит. Це страховка. Якщо PATCH переривається посередині частини, наприклад, після трьох мегабайт із п'ятимегабайтного фрагмента, з'єднання розривається. Коли клієнт відновлює доступ до мережі, він надсилає HEAD-запит на URL завантаження. Сервер відповідає поточним значенням Upload-Offset. Клієнт порівнює