Impostazione di un flusso video con Spring Framework e Chrome
Stiamo scrivendo un servizio Spring che rende disponibile un endpoint HTTP attraverso il quale è possibile eseguire lo streaming di un file video (o audio) da uno store Amazon S3. L'idea di base è che puoi digitare un URL nella barra degli indirizzi di Google Chrome e il servizio preleverà il file da S3 e lo trasmetterà in streaming, in modo tale che l'utente possa iniziare a guardare immediatamente senza dover attendere il download per completo e che l'utente può fare clic su un punto casuale nella barra di avanzamento del video e iniziare immediatamente a guardare il video da quel punto.
Il modo in cui capisco che questo dovrebbe funzionare in teoria è che Chrome inizia a scaricare il file. Il servizio risponde con HTTP 200 e include un Accept-Ranges: bytes
e Content-Length: filesize
un'intestazione. Il filesize
è noto, perché possiamo interrogarlo come metadati da S3 senza recuperare l'intero file. L'inclusione di queste intestazioni fa sì che il browser annulli il download e richieda nuovamente il file con Range: bytes=0-whatever
un'intestazione (dove whatever
è una dimensione del blocco che decide Chrome). Il servizio quindi risponde con HTTP 206 (contenuto parziale) e l'intervallo di byte richiesto, che possiamo determinare facilmente perché S3 supporta lo stesso protocollo di intervallo. Chrome richiede quindi blocchi successivi dal servizio, fino al termine del flusso.
Sul lato Spring, stiamo inviando i dati in a ResponseEntity<InputStreamResource>
(come da this SO answer ).
Tuttavia, osserviamo in pratica che mentre Chrome annulla la sua prima richiesta dopo poche centinaia di byte. Tuttavia, invia una seconda richiesta con Range: bytes=0-
un'intestazione, chiedendo di fatto l'intero file. Il server risponde con un HTTP 206. Di conseguenza, ha scaricato solo poche centinaia di byte di video e ovviamente il video non viene riprodotto.
È interessante notare che in Firefox funziona tutto correttamente. Sfortunatamente, la nostra app deve supportare Chrome. Ci stiamo perdendo qualche parte del protocollo?
Risposte
Si scopre che abbiamo avuto un errore off-by-one nell'intestazione della Content-Range
risposta.
La sintassi è Content-Range: bytes start-end/total
. Con a total
of 10
, se vuoi ottenere l'intero intervallo, devi specificare bytes 0-9/10
, not 0-10/10
, quale era quello che stavamo facendo.
Ovviamente con le dimensioni maggiori dei file reali e gli intervalli effettivi di blocchi nel mezzo di tali file, questo errore era molto più difficile da notare rispetto all'esempio artificioso nel paragrafo precedente... ಠ_ಠ