Diferentes implementaciones de codificación de transferencia y longitud del contenido
Vi el siguiente código en un proyecto no hace mucho:
?
HttpServletResponse respuesta = (HttpServletResponse)servletResponse
response; . setHeader("Transfer-Encoding", "utf8");
filterChain.doFilter(servletRequest, servletResponse);
La intención es codificar la salida, pero la respuesta es incorrecta. encabezado usado. Como resultado, este encabezado de respuesta incorrecto trae muchos problemas a los programas cliente posteriores. Es necesario entender esto en detalle.
Codificación de datos de transferencia: codificación de transferencia (codificación de transferencia)
La codificación de datos se refiere a cómo utilizar garantías para garantizar la seguridad de los datos y la transmisión exitosa durante la transmisión de datos a través de la red. Los datos se pueden transmitir en segmentos o se pueden transmitir sin segmentos y los datos originales se pueden utilizar directamente.
Los valores válidos son: Retransmisión e identidad:
Codificación del contenido de la transmisión:
Codificación del contenido
Codificación del contenido, es decir, toda la información de datos Qué codificación se utiliza para codificar en el lado del almacén de datos, y luego el cliente invierte la codificación para obtener el contenido original. La codificación de contenido aquí se refiere principalmente a la codificación de compresión, es decir, compresión del lado del servidor y descompresión del lado del cliente.
Los valores a los que puede hacer referencia son: gzip, comprimir, deflactar e identidad.
Formato de contenido de transmisión: Content-Type
Formato de contenido, es decir, el formato en el que finalmente se muestran los datos recibidos en el navegador. El formato de contenido también admite un conjunto de caracteres de parámetro opcional, que es el conjunto de caracteres del contenido real. Los juegos de caracteres permiten al cliente decodificar los datos y, en última instancia, muestran texto legible (en lugar de bytes [] o galimatías).
Estos tres tipos de información descriptiva se pueden representar mediante la siguiente figura (extraída de "La guía definitiva de HTTP"):
Como se puede ver en la figura anterior, de hecho , el contenido del filtro original puede hacer referencia al siguiente contenido:
?
response.setContentType("text/html; charset=UTF8"); >//o
response.setContentType("application/json; charset=UTF8" );
Longitud del contenido: Longitud del contenido
Longitud del contenido, es decir, información que indica la duración efectiva de todo el contenido de la transmisión. El cliente puede utilizar esta información de encabezado para determinar si los datos recibidos se han recibido en su totalidad. Esta codificación entra en conflicto con la codificación de transferencia porque la codificación de transferencia cambia la organización de los datos mediante un procesamiento adicional, cambiando así la longitud real de los datos. Si el cliente aún sigue la longitud del contenido original, no podrá recibir los datos completos. .
Debido al conflicto entre la codificación de transferencia y la longitud del contenido, tanto el servidor como el cliente tienen implementaciones que admiten el procesamiento de datos correspondiente. Todo el proceso se maneja según RFC 2616.
Reglas de procesamiento: (ion: cerrar, es decir, el cliente solo solicitará una vez y no usará Keep-Alive. En este caso, no es necesario usar transmisión de retransmisión,
/Debido a que el cliente necesita saber cuándo se han transmitido los datos, use read() == -1 para determinar
if (entityBody amp; amp; http11 amp; amp; ! ConnectionClosePresent) {
// Utilice ChunkedOutputFilter para procesar los datos transmitidos dos veces, es decir,
getOutputBuffer ().addActiveFilter
(outputFilters[Constants.CHUNKED_FILTER]); p >
contentDelimitation = true;
headers.addValue(addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
} else {
//Finalmente use el método de transferencia de datos sin procesar
getOutputBuffer().addActiveFilter
(outputFilters[Constants.IDENTITY_FILTER]);
}
}
Este código se llamará cuando la aplicación haya terminado de procesar la lógica o llamar a Response.outputStream. Para obtener una lógica de procesamiento detallada, consulte los comentarios anteriores.
Debería ser. Tenga en cuenta que, dado que Http funciona a través de TCP/IP, las garantías de integridad de los datos ya no son manejadas por Http. Por lo tanto, confiar en los relés para garantizar la integridad de los datos ya no tiene mucho sentido, el relé se puede procesar especialmente para informar al cliente (identificado). por la longitud del encabezado 0) a los que se han respondido los datos, el cliente puede procesar y usar la conexión nuevamente en el siguiente proceso. Por lo tanto, en el procesamiento troncalizado anterior, si Tomcat no cree que sea necesario usar troncalizado (como. como modelo de conexión de solicitud única: cerrar), por lo que no forzará el uso de
implementación de cliente troncalizado de HttpClient
httpclient (versión 4.3.3). se implementa principalmente en la clase EntityDeserializer, es decir, cómo obtener datos y decodificarlos de forma inversa. El método de implementación es doDeserialize, y la implementación principal es la siguiente:
?
final long len = this.lenStrategy.determineLength(message);
if (len = = ContentLengthStrategy.CHUNKED) {
entity.setContent(new ContentLengthInputStream(inbuffer, len));
}
Es decir, determinando el valor de longitud para determinar si Utilice un análisis de datos diferente. El flujo de datos analizado se procesará de 3 maneras diferentes***, la fragmentación y la identificación se especificarán en la codificación de transferencia y la longitud del contenido.
La lógica para determinar la longitud es la siguiente:
?
final Header transferEncodingHeader = message.getFirstHeader(HTTP.TRANSFER_ENCODING
<); p> // Si está presente, utilizamos codificación de transferencia, ignorando la longitud del contenido. 4 Elemento 3// Como se describe en RFC26216 4.4, la codificación de transferencia se procesa primero
if (transferEncodingHeader! = null) {
Final HeaderElement[] codificaciones ;
codificaciones = transferEncodingHeader.getElements();
//La codificación fragmentada debe ser la última codificación que aplica RFC2616, 14.41
final int len = codificaciones .error
if (HTTP.IDENTITY_CODING.equalsIgnoreCase(transferEncodingHeader.getValue())){
return IDENTITY;
} else if ((len gt; 0) amp; ) {
contenido largo = -1;
Encabezado final[] encabezados = message.getHeaders(HTTP.CONTENT_LEN);
contentlen = Long.parseLong( header .getValue());
}
if (contentlent; = 0) {
return contentlen;
} else {
return IDENTITY;
}
}}
}
En el contenido anterior, vemos IDENTITY Procesado más. Esto puede explicarse por el uso de IDENTIDAD, que es la forma más primitiva de manejar cualquier cosa que no se pueda analizar.
A través de la implementación anterior, podemos comprender las diferentes respuestas y lógica de procesamiento del cliente después de recibir los datos, lo que también puede explicar las situaciones extrañas que ocurren en el proyecto.