Настройка видеопотока с помощью Spring Framework и Chrome

Aug 19 2020

Мы пишем службу Spring, которая делает доступной конечную точку HTTP, через которую можно транслировать видео (или аудио) файл из магазина Amazon S3. Основная идея заключается в том, что вы можете ввести URL-адрес в адресной строке Google Chrome, и служба будет извлекать файл из S3 и передавать его таким образом, чтобы пользователь мог сразу начать просмотр, не дожидаясь загрузки на завершено, и что пользователь может щелкнуть случайное место на индикаторе выполнения видео и сразу же начать просмотр видео с этого места.

Насколько я понимаю, это должно работать в теории, так это то, что Chrome начинает загрузку файла. Служба отвечает HTTP 200 и включает в себя Accept-Ranges: bytesи в Content-Length: filesizeзаголовок. Это filesizeизвестно, потому что мы можем запросить это как метаданные из S3, не извлекая весь файл. Включение этих заголовков приводит к тому, что браузер отменяет загрузку и снова запрашивает файл с Range: bytes=0-whateverзаголовком (где whateverопределяется размер блока, который определяет Chrome). Затем служба отвечает HTTP 206 (частичное содержимое) и запрошенным диапазоном байтов, который мы можем легко определить, поскольку S3 поддерживает тот же протокол диапазона. Затем Chrome запрашивает у службы последовательные порции, пока поток не закончится.

Со стороны Spring мы отправляем данные в виде ResponseEntity<InputStreamResource>(согласно этому ответу SO ).

Однако на практике мы наблюдаем, что Chrome отменяет свой первый запрос после нескольких сотен байт. Однако он отправляет второй запрос с Range: bytes=0-заголовком, фактически запрашивая весь файл. Сервер отвечает HTTP 206. В результате он загрузил только несколько сотен байтов видео, и видео, очевидно, не начинает воспроизводиться.

Что интересно, в Firefox все работает исправно. К сожалению, наше приложение должно поддерживать Chrome. Нам не хватает какой-то части протокола?

Ответы

2 jqno Sep 01 2020 at 21:28

Оказывается, в Content-Rangeзаголовке ответа у нас была ошибка, не равная единице .

Синтаксис такой Content-Range: bytes start-end/total. С totalо 10, если вы хотите , чтобы весь диапазон, вам нужно указать bytes 0-9/10, не 0-10/10, что было то , что мы делаем.

Конечно, с большими размерами реальных файлов и фактическим диапазоном фрагментов в середине таких файлов эту ошибку было намного труднее заметить, чем в надуманном примере в предыдущем абзаце ... ಠ_ಠ