Menyiapkan aliran video dengan Spring Framework dan Chrome

Aug 19 2020

Kami sedang menulis layanan Spring yang membuat titik akhir HTTP tersedia di mana file video (atau audio) dari toko Amazon S3 dapat dialirkan. Ide dasarnya adalah Anda dapat mengetikkan url di bilah alamat Google Chrome, dan layanan akan mengambil file dari S3 dan mengalirkannya, sedemikian rupa sehingga pengguna dapat langsung mulai menonton tanpa harus menunggu unduhan untuk selesai, dan pengguna dapat mengeklik tempat acak di bilah kemajuan video dan segera mulai menonton video dari tempat itu.

Cara saya memahami ini seharusnya berfungsi secara teori, adalah bahwa Chrome mulai mengunduh file. Layanan merespon dengan HTTP 200 dan menyertakan sebuah Accept-Ranges: bytesdan sebuah Content-Length: filesizeheader. Ini filesizediketahui, karena kita dapat mengkueri itu sebagai metadata dari S3 tanpa mengambil seluruh file. Memasukkan tajuk ini menyebabkan peramban membatalkan unduhan, dan meminta file lagi dengan Range: bytes=0-whatevertajuk (dengan whateverbeberapa ukuran potongan yang diputuskan oleh Chrome). Layanan kemudian merespons dengan HTTP 206 (konten parsial) dan rentang byte yang diminta, yang dapat kita tentukan dengan mudah karena S3 mendukung protokol rentang yang sama. Chrome kemudian meminta potongan yang berurutan dari layanan, hingga streaming berakhir.

Di sisi Spring, kami mengirimkan data dalam ResponseEntity<InputStreamResource>(sesuai jawaban SO ini ).

Namun, dalam praktiknya kami mengamati bahwa Chrome membatalkan permintaan pertamanya setelah beberapa ratus byte. Namun, ini mengirimkan permintaan kedua dengan Range: bytes=0-header, secara efektif meminta seluruh file. Server merespons dengan HTTP 206. Akibatnya, hanya mengunduh beberapa ratus byte video, dan video jelas tidak mulai diputar.

Menariknya, di Firefox semuanya berfungsi dengan baik. Sayangnya, aplikasi kami harus mendukung Chrome. Apakah kita melewatkan beberapa bagian dari protokol?

Jawaban

2 jqno Sep 01 2020 at 21:28

Ternyata kami mengalami kesalahan off-by-one di Content-Rangeheader respons.

Sintaksnya adalah Content-Range: bytes start-end/total. Dengan totaldari 10, jika Anda ingin mendapatkan keseluruhan rentang, Anda perlu menentukan bytes 0-9/10, bukan 0-10/10, yang kami lakukan.

Tentu saja dengan ukuran file nyata yang lebih besar, dan rentang potongan sebenarnya di tengah file tersebut, kesalahan ini jauh lebih sulit untuk diperhatikan daripada contoh yang dibuat di paragraf sebelumnya ... ಠ_ಠ