Configurer un flux vidéo avec Spring Framework et Chrome

Aug 19 2020

Nous écrivons un service Spring qui met à disposition un point de terminaison HTTP via lequel un fichier vidéo (ou audio) d'un magasin Amazon S3 peut être diffusé en continu. L'idée de base est que vous pouvez saisir une URL dans la barre d'adresse de Google Chrome, et le service récupérera le fichier à partir de S3 et le diffusera, de manière à ce que l'utilisateur puisse commencer à regarder immédiatement sans avoir à attendre un téléchargement pour terminé, et que l'utilisateur peut cliquer sur un endroit aléatoire dans la barre de progression de la vidéo et commencer immédiatement à regarder la vidéo à partir de cet endroit.

La façon dont je comprends que cela devrait fonctionner en théorie, c'est que Chrome commence à télécharger le fichier. Le service répond avec HTTP 200 et inclut un Accept-Ranges: byteset un Content-Length: filesizeen-tête. Le filesizeest connu, car nous pouvons interroger cela en tant que métadonnées à partir de S3 sans récupérer l'intégralité du fichier. L'inclusion de ces en-têtes oblige le navigateur à annuler le téléchargement et à redemander le fichier avec un Range: bytes=0-whateveren-tête (où whateverest une taille de bloc que Chrome décide). Le service répond ensuite avec HTTP 206 (Contenu partiel) et la plage d'octets demandée, que nous pouvons déterminer facilement car S3 prend en charge le même protocole de plage. Chrome demande ensuite des morceaux successifs au service, jusqu'à la fin du flux.

Du côté du printemps, nous envoyons les données dans un ResponseEntity<InputStreamResource>(selon cette réponse SO ).

Cependant, on observe en pratique que tout Chrome annule sa première requête au bout de quelques centaines d'octets. Cependant, il envoie une deuxième requête avec un Range: bytes=0-en-tête, demandant effectivement l'intégralité du fichier. Le serveur répond par un HTTP 206. En conséquence, il n'a téléchargé que quelques centaines d'octets de vidéo, et la vidéo ne démarre évidemment pas.

Fait intéressant, dans Firefox, tout fonctionne correctement. Malheureusement, notre application doit prendre en charge Chrome. Manquons-nous une partie du protocole?

Réponses

2 jqno Sep 01 2020 at 21:28

Il s'avère que nous avons eu une erreur de un par un dans l'en- Content-Rangetête de réponse.

La syntaxe est Content-Range: bytes start-end/total. Avec un totalde 10, si vous voulez obtenir toute la plage, vous devez spécifier bytes 0-9/10, et non 0-10/10, ce que nous faisions.

Bien sûr, avec les tailles plus grandes des fichiers réels et les plages réelles de morceaux au milieu de ces fichiers, cette erreur était beaucoup plus difficile à remarquer que dans l'exemple artificiel du paragraphe précédent... ಠ_ಠ