2010-03-10 4 views
27

J'essaie de peser le pour et le contre de la définition de l'en-tête HTTP Content-Length par rapport à l'utilisation du codage en segments pour renvoyer [probablement] de gros fichiers de mon serveur. L'un ou l'autre est nécessaire pour être conforme aux spécifications HTTP 1.1 en utilisant des connexions persistantes. Je vois l'avantage de l'être d'en-tête Content-Length:En-tête Content-Length ou codage en segments

  • boîtes de dialogue de téléchargement peuvent afficher la barre de progression précise
  • client sait dès le départ si le fichier peut/ne peut pas être trop grand pour eux ingèrent

Le inconvénient est de devoir calculer la taille avant de retourner l'objet qui n'est pas toujours pratique et pourrait ajouter à l'utilisation du serveur/base de données. L'inconvénient de l'encodage en bloc est la petite surcharge de l'ajout de la taille du bloc avant chaque bloc et la barre de progression du téléchargement. Des pensées? Toutes les autres considérations HTTP pour les deux méthodes que je n'ai peut-être pas pensé?

+1

Est-ce un étant donné que votre contenu est statique et sa longueur est connue a priori? Sinon, le partage serait beaucoup plus rapide pour les fichiers volumineux. –

Répondre

27

Utilisez Content-Length, définitivement. L'utilisation du serveur à partir de ce sera presque inexistante et le bénéfice pour vos utilisateurs sera grand. Pour le contenu dynamique, il est également très 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 de contenu partiel/service d'octets, c'est-à-dire, possibilité de redémarrer les téléchargements. See here for a byte-range example (l'exemple est en PHP, mais est applicable dans n'importe quelle langue). Vous avez besoin de Content-Length pour diffuser du contenu partiel.

Bien sûr, ce ne sont pas des balles en argent: pour les médias en continu, il est inutile d'utiliser la mise en 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 Content-Length et le service d'octets ont beaucoup de sens (le redémarrage d'un téléchargement échoué est possible).

Personnellement, je diffuse la longueur du contenu à chaque fois que je la 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 sont téléchargées plus rapidement grâce à gzip).

+1

Je ne vois pas comment la gamme d'octets servant (essentiellement: "reprendre les téléchargements") est bénéfique dans ce cas particulier. Cela nécessite notamment que la longueur du contenu soit connue à l'avance. Vous pouvez alors tout aussi bien définir la longueur du contenu. – BalusC

+0

@BalusC: Content-Length est un ** pré-requis ** pour la diffusion d'octets. Cas d'utilisation typique: l'utilisateur télécharge un fichier de 10 Mo sur sa connexion WiFi, le signal baisse de 7 Mo dans le téléchargement. Sans reprise, elle doit à nouveau télécharger l'ensemble des 10 Mo, ce qui est assez énervant pour elle; avec CV, il ne reste plus que 3 Mo. La plupart des navigateurs modernes supportent cela. – Piskvor

+0

Oui, je sais. Peut-être que vous ne m'avez pas compris? Je dis juste que je ne vois pas comment cela est lié à la "longueur du contenu" v.s. "transfert-encodage: chunked" question. D'ailleurs, l'historique de l'OP me dit que sa langue principale est Java, dans ce cas cet exemple 'FileServlet' peut être plus utile: http://balusc.blogspot.com/2009/02/fileservlet-supporting-resume- and.html – BalusC

10

Si la longueur du contenu est connue à l'avance, alors je préférerais certainement l'envoyer au-dessus 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, n'importe quel langage de programmation respecté et le SGBDR permettent 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 (par exemple, si vous voulez compresser plusieurs fichiers ensemble et les envoyer ensemble), l'envoyer en morceaux peut être plus rapide que de le mettre en mémoire tampon ou de le écrire d'abord sur le système de fichiers du disque local. Mais cela a en effet un impact négatif sur l'expérience de l'utilisateur car la progression du téléchargement est inconnue. L'impatient peut alors annuler le téléchargement et avancer.

Un autre avantage de connaître la longueur du contenu 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 here un article avec des informations de fond plus techniques et un exemple Java Servlet qui fait cela.

0

Content-Length

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

L'en-tête Content-Length n'autorise pas la diffusion en continu, mais il est utile pour les fichiers binaires de grande taille dans lesquels vous souhaitez prendre en charge la diffusion partielle de contenu. Cela signifie essentiellement des téléchargements résumables, des téléchargements en pause, 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 Byte serving.

Transfer-Encoding

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 par chunked et n'affectent pas la représentation du contenu. Officiellement, un client HTTP est destiné à envoyer une requête 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 codages chunked.

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

Content-Encoding

Il est également possible de compresser les données CHUNKED ou non CHUNKED. Ceci est pratiquement fait via l'en-tête Content-Encoding. Notez que le Content-Length est égal à la longueur du corps après le Content-Encoding. Cela signifie que si vous avez gzippé votre réponse, le calcul de la longueur se produit après la compression. Vous devrez être en mesure 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 utilisant le codage en bloc, l'algorithme de compression doit également prendre en charge le traitement en ligne. Heureusement, gzip supporte 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 « bout à bout » schéma de codage, ce qui signifie que le client final ou serveur finale est censé décoder le contenu. Les proxies au milieu ne sont pas censés décoder le contenu.

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

Cependant, cela est très rarement pris en charge. Donc, vous devriez seulement utiliser Content-Encoding pour votre compression dès maintenant.

Chunked vs Store & Forward