respuesta que personalizadas modificar mensajes length headers encabezado ejemplo content comandos cabeceras cabecera performance http chunked-encoding content-length

performance - que - Cabecera Content-Length frente a codificación fragmentada



modificar cabeceras http (3)

Estoy tratando de sopesar los pros y los contras de establecer el encabezado HTTP Content-Length contra el uso de codificación fragmentada para devolver [posiblemente] archivos grandes de mi servidor. Se necesita uno u otro para cumplir con las especificaciones de HTTP 1.1 utilizando conexiones persistentes. Veo la ventaja de que el encabezado Content-Length es:

  • Los diálogos de descarga pueden mostrar una barra de progreso precisa
  • El cliente lo sabe por adelantado si el archivo puede / no ser demasiado grande para que lo ingieran

La desventaja es tener que calcular el tamaño antes de devolver el objeto que no siempre es práctico y podría agregarse a la utilización del servidor / base de datos. La desventaja de la codificación fragmentada es la pequeña sobrecarga de agregar el tamaño del fragmento antes de cada fragmento y la barra de progreso de la descarga. ¿Alguna idea? ¿Alguna otra consideración HTTP para ambos métodos en la que no haya pensado?


Largancia de contenido

El encabezado Content-Length determina la longitud del byte del cuerpo de solicitud / respuesta. Si no especifica el encabezado Content-Length , los servidores HTTP agregarán implícitamente un encabezado Transfer-Encoding: chunked . El Content-Length y Transfer-Encoding no se deben usar juntos. El receptor no tendrá idea de la longitud del cuerpo y no puede estimar el tiempo de finalización de la descarga. Si agrega un encabezado Content-Length , asegúrese de que coincida con todo el cuerpo en bytes, si es incorrecto, el comportamiento de los receptores no está definido.

El encabezado Content-Length no permitirá la transmisión, pero es útil para archivos binarios grandes, donde se desea admitir la publicación de contenido parcial. Esto básicamente significa descargas reanudables, descargas pausadas, descargas parciales y descargas multihomicidas. Esto requiere el uso de un encabezado adicional llamado Range . Esta técnica se llama servicio Byte .

Transferencia-Codificación

El uso de Transfer-Encoding: chunked es lo que permite la transmisión dentro de una sola solicitud o respuesta. Esto significa que los datos se transmiten en forma fragmentada y no afectan la representación del contenido.

Oficialmente, un cliente HTTP debe enviar una solicitud con un campo de encabezado TE que especifique qué tipos de codificación de transferencia el cliente está dispuesto a aceptar. Esto no siempre se envía, sin embargo, la mayoría de los servidores suponen que los clientes pueden procesar codificaciones chunked .

La codificación de transferencia chunked hace un mejor uso de las conexiones TCP persistentes, que HTTP 1.1 supone que son verdaderas por defecto.

Content-Encoding

También es posible comprimir datos fragmentados o no fragmentados. Esto se hace prácticamente a través del encabezado Content-Encoding .

Tenga en cuenta que Content-Length es igual a la longitud del cuerpo después de Content-Encoding . Esto significa que si ha descomprimido su respuesta, entonces el cálculo de la longitud ocurre después de la compresión. Tendrá que poder cargar todo el cuerpo en la memoria si desea calcular la longitud (a menos que tenga esa información en otro lugar).

Al transmitir usando codificación fragmentada, el algoritmo de compresión también debe admitir el procesamiento en línea. Afortunadamente, gzip admite la compresión de flujo. Creo que el contenido se comprime primero y luego se corta en trozos. De esta forma, los fragmentos se reciben, luego se descomprimen para adquirir el contenido real. Si fuera al revés, obtendrás el flujo comprimido, y luego descomprimirnos nos daría trozos. Lo cual no tiene sentido.

Una respuesta típica de flujo comprimido puede tener estos encabezados:

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

Semánticamente, el uso de Content-Encoding indica un esquema de codificación de "extremo a extremo", lo que significa que solo se supone que el cliente final o el servidor final decodifican el contenido. Los apoderados intermedios no deben decodificar el contenido.

Si desea permitir que los proxies en el medio decodifiquen el contenido, el encabezado correcto para usar es, de hecho, el encabezado Transfer-Encoding . Si la solicitud HTTP poseía un encabezado TE: gzip chunked , entonces es legal responder con Transfer-Encoding: gzip chunked .

Sin embargo, esto rara vez es compatible. Entonces, solo debería usar Content-Encoding para su compresión en este momento.

Chunked vs Store & Forward


Si la longitud del contenido se conoce de antemano, ciertamente lo preferiría antes que enviar fragmentos. Si hay medios de archivos estáticos en el sistema de archivos del disco local o en una base de datos, entonces cualquier lenguaje de programación respetuoso y RDBMS proporciona formas de obtener la longitud del contenido de antemano. Deberías hacer uso de eso.

Por otro lado, si la longitud del contenido es realmente impredecible de antemano (por ejemplo, cuando tu intención es comprimir varios archivos y enviarlo como uno solo), enviarlos en trozos puede ser más rápido que almacenarlos en la memoria del servidor o escribir en un disco local sistema de archivos primero. Pero esto de hecho tiene un impacto negativo en la experiencia del usuario porque el progreso de la descarga es desconocido. El impaciente puede abortar la descarga y avanzar.

Otro beneficio de saber la longitud del contenido de antemano es la capacidad de reanudar las descargas. Veo en su historial de publicaciones que su lenguaje de programación principal es Java; aquí puede encontrar un artículo con más información técnica de fondo y un ejemplo de Java Servlet que hace eso.


Use Content-Length, definitivamente. La utilización del servidor de esto será casi inexistente y el beneficio para sus usuarios será grande.

Para contenido dinámico, también es bastante simple agregar compatibilidad de respuesta comprimida ( gzip ). Eso requiere buffer de salida, que a su vez le da la longitud del contenido. (no práctico con descargas de archivos o contenido ya comprimido (sonido, imágenes)).

Considere también agregar compatibilidad con contenido parcial / servicio de rango de bytes, es decir, capacidad para reiniciar descargas. Vea aquí un ejemplo de rango de bytes (el ejemplo está en PHP, pero es aplicable en cualquier idioma). Necesita Content-Length cuando se sirve contenido parcial.

Por supuesto, esas no son balas de plata: para los medios de transmisión en vivo, no tiene sentido usar el buffer de salida o el tamaño de respuesta; para archivos grandes, el almacenamiento en búfer de salida no tiene sentido, pero la longitud del contenido y la publicación de bytes tienen mucho sentido (es posible reiniciar una descarga fallida).

Personalmente, sirvo Content-Length cada vez que lo sé; para descargar archivos, verificar el tamaño del archivo es insignificante en términos de recursos. Resultado: el usuario tiene una barra de progreso determinada (y las páginas dinámicas se descargan más rápido gracias a gzip).