web-dev-qa-db-fra.com

En-tête Content-Length versus codage en morceaux

J'essaie de peser les avantages et les inconvénients de la définition du Content-Length En-tête HTTP par rapport à l'utilisation d'un codage en morceaux pour renvoyer [éventuellement] des fichiers volumineux depuis mon serveur. L'un ou l'autre est nécessaire pour être conforme aux spécifications HTTP 1.1 à l'aide de connexions persistantes. Je vois l'avantage du Content-Length l'en-tête étant:

  • Les boîtes de dialogue de téléchargement peuvent afficher une barre de progression précise
  • Le client sait d'avance si le fichier peut/peut ne pas être trop volumineux pour être ingéré

L'inconvénient est de devoir calculer la taille avant de renvoyer l'objet, ce qui n'est pas toujours pratique et pourrait augmenter l'utilisation du serveur/base de données. L'inconvénient de l'encodage en morceaux est le petit surcoût lié à l'ajout de la taille des blocs avant chaque bloc et de la barre de progression du téléchargement. Des pensées? D'autres considérations HTTP pour les deux méthodes auxquelles je n'ai peut-être pas pensé?

35
Gandalf

Utilisez certainement Content-Length. L'utilisation du serveur à partir de cela sera presque inexistante et l'avantage pour vos utilisateurs sera important.

Pour le contenu dynamique, il est également assez simple d'ajouter un support de réponse compressé ( gzip ). Cela nécessite une mise en mémoire tampon de sortie, qui à son tour vous donne la longueur du contenu. (pas pratique avec des téléchargements de fichiers ou du contenu déjà compressé (son, images)).

Pensez également à ajouter la prise en charge du contenu partiel /portion de plage d'octets - c'est-à-dire la possibilité de redémarrer les téléchargements. Voir ici pour un exemple de plage d'octets (l'exemple est en PHP, mais est applicable dans n'importe quel langage). Vous avez besoin de Content-Length lorsque vous diffusez du contenu partiel.

Bien sûr, ce ne sont pas des balles d'argent: pour la diffusion multimédia en continu, il est inutile d'utiliser la mémoire tampon de sortie ou la taille de la réponse; pour les fichiers volumineux, la mise en mémoire tampon de sortie n'a pas de sens, mais la longueur du contenu et le service d'octets ont beaucoup de sens (le redémarrage d'un téléchargement ayant échoué est possible).

Personnellement, je sers Content-Length chaque fois que je le connais; pour le téléchargement de fichiers, la vérification de la taille du fichier est insignifiante en termes de ressources. Résultat: l'utilisateur dispose d'une barre de progression déterminée (et les pages dynamiques se téléchargent plus rapidement grâce à gzip).

Si la longueur du contenu est connue à l'avance, je la préférerais certainement plutôt que d'envoyer des morceaux. S'il existe des moyens de fichiers statiques sur le système de fichiers du disque local ou dans une base de données, alors tout langage de programmation et RDBMS auto-respecté fournit des moyens d'obtenir la longueur du contenu à l'avance. Vous devriez en faire usage.

D'un autre côté, si la longueur du contenu est vraiment imprévisible à l'avance (par exemple, lorsque votre intention est de compresser plusieurs fichiers ensemble et de les envoyer en un seul), leur envoi en plusieurs morceaux peut être plus rapide que de le mettre en mémoire tampon dans la mémoire du serveur ou d'écrire sur le disque local. système de fichiers en premier. Mais cela a en effet un impact négatif sur l'expérience utilisateur car la progression du téléchargement est inconnue. Les impatients peuvent alors abandonner le téléchargement et avancer.

Un autre avantage de connaître la longueur du contenu à l'avance est la possibilité de reprendre les téléchargements. Je vois dans votre historique de publication que votre langage de programmation principal est Java; vous pouvez trouver ici un article avec des informations de base plus techniques et un Java exemple de servlet qui fait cela.

12
BalusC

Longueur du contenu

Le Content-Length l'en-tête détermine la longueur en octets du corps de la demande/réponse. Si vous négligez de spécifier le Content-Length en-tête, les serveurs HTTP ajouteront implicitement un Transfer-Encoding: chunked entête. Le Content-Length et Transfer-Encoding l'en-tête ne doit pas être utilisé ensemble. Le récepteur n'aura aucune idée de la longueur du corps et ne pourra pas estimer le temps de fin de téléchargement. Si vous ajoutez un Content-Length en-tête, assurez-vous qu'il correspond au corps entier en octets, s'il est incorrect, le comportement des récepteurs n'est pas défini.

Le Content-Length l'en-tête ne permet pas la diffusion en continu, mais il est utile pour les gros fichiers binaires, où vous souhaitez prendre en charge la diffusion de contenu partiel. Cela signifie essentiellement des téléchargements pouvant être repris, des téléchargements suspendus, des téléchargements partiels et des téléchargements multi-hébergés. Cela nécessite l'utilisation d'un en-tête supplémentaire appelé Range. Cette technique est appelée portion d'octets .

Codage de transfert

L'utilisation de Transfer-Encoding: chunked est ce qui permet le streaming dans une seule demande ou réponse. Cela signifie que les données sont transmises de manière fragmentée et n'affectent pas la représentation du contenu.

Officiellement, un client HTTP est censé envoyer une demande avec un champ d'en-tête TE qui spécifie les types de codages de transfert que le client est prêt à accepter. Ce n'est pas toujours envoyé, mais la plupart des serveurs supposent que les clients peuvent traiter les encodages chunked.

Le codage de transfert chunked fait un meilleur usage des connexions persistantes TCP, que HTTP 1.1 suppose être vraies par défaut.

Encodage de contenu

Il est également possible de compresser des données fragmentées ou non fragmentées. Cela se fait pratiquement via le Content-Encoding entête.

Notez que le Content-Length est égal à la longueur du corps après le Content-Encoding. Cela signifie que si vous avez compressé votre réponse, le calcul de la longueur se produit après la compression. Vous devrez être capable de charger le corps entier en mémoire si vous voulez calculer la longueur (sauf si vous avez cette information ailleurs).

Lors de la diffusion en continu à l'aide d'un codage fragmenté, l'algorithme de compression doit également prendre en charge le traitement en ligne. Heureusement, gzip prend en charge la compression de flux. Je crois que le contenu est compressé en premier, puis découpé en morceaux. De cette façon, les morceaux sont reçus, puis décompressés pour acquérir le contenu réel. Si c'était l'inverse, vous obtiendrez le flux compressé, puis la décompression nous donnerait des morceaux. Ce qui n'a pas de sens.

Une réponse de flux compressé typique peut avoir ces en-têtes:

Content-Type: text/html
Content-Encoding: gzip
Transfer-Encoding: chunked

Sémantiquement, l'utilisation de Content-Encoding indique un schéma de codage "de bout en bout", ce qui signifie que seul le client final ou le serveur final est censé décoder le contenu. Les mandataires au milieu ne sont pas censés décoder le contenu.

Si vous voulez autoriser les mandataires au milieu à décoder le contenu, l'en-tête correct à utiliser est en fait le Transfer-Encoding entête. Si la requête HTTP possédait un TE: gzip chunked en-tête, il est alors légal de répondre avec Transfer-Encoding: gzip chunked.

Cependant, cela est très rarement pris en charge. Vous ne devez donc utiliser que Content-Encoding pour votre compression en ce moment.

Chunked vs Store & Forward

5
Dhairya Lakhera