Android: la comunicación HTTP debe utilizar "Accept-Encoding: gzip"

109

Tengo una comunicación HTTP con un servidor web que solicita datos JSON. Me gustaría comprimir este flujo de datos con Content-Encoding: gzip. ¿Hay alguna forma de que pueda configurar Accept-Encoding: gzipen mi HttpClient? La búsqueda gzipen las Referencias de Android no muestra nada relacionado con HTTP, como puede ver aquí .

znq
fuente
1
Android-WebRequest admite GZIP y respuestas sin comprimir automáticamente, por ejemplo, con new WebRequest().get().to("http://www.example.com/").askForGzip(true).executeSync(). Específicamente, el método parseResponse (...) debería ser lo que estás buscando.
caw

Respuestas:

174

Debe usar encabezados http para indicar que una conexión puede aceptar datos codificados en gzip, por ejemplo:

HttpUriRequest request = new HttpGet(url);
request.addHeader("Accept-Encoding", "gzip");
// ...
httpClient.execute(request);

Verifique la respuesta para la codificación del contenido:

InputStream instream = response.getEntity().getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
    instream = new GZIPInputStream(instream);
}
Bakhtiyor
fuente
7
Esa es una respuesta excelente y muy útil con todos los detalles que necesitaba. Muchas gracias. Un comentario: en lugar de addHeader usé setHeader. Por lo que entiendo, esto sobrescribe el "Accept-Encoding" existente, si lo hay. No estoy seguro de qué enfoque es el correcto / mejor. Para sobrescribir un encabezado existente para asegurarse de que tiene el valor correcto, o para agregarlo en caso de que pueda haber otros encabezados Accept-Encoding en paralelo.
znq
¿Dónde pones el instream entonces?
Mikey
7
esto no convierte la solicitud en gzip, solo le dice al servidor que puede aceptar una respuesta en gzip.
Jeffrey Blattman
1
Para cualquiera que también tenga problemas para poner esto en funcionamiento para los servicios de Google, aquí hay dos problemas que me tomó bastante tiempo descubrir: (1) algunos servicios de Google requieren que la cadena de agente de usuario proporcionada por el cliente contenga la cadena gzippara habilitar realmente compresión gzip. (2) tenga en cuenta que es posible que el servidor no gzip la respuesta si es demasiado pequeña ...
sven
Mi problema es que el encabezado gzip no se ve por ningún lado. Estoy usando Wireshark para rastrear la red en el lado del servidor y no veo rastro del encabezado "gzip" que agregué en Android ...
Ted
33

Si está utilizando el nivel de API 8 o superior, existe AndroidHttpClient .

Tiene métodos de ayuda como:

public static InputStream getUngzippedContent (HttpEntity entity)

y

public static void modifyRequestToAcceptGzipResponse (HttpRequest request)

conduciendo a un código mucho más sucinto:

AndroidHttpClient.modifyRequestToAcceptGzipResponse( request );
HttpResponse response = client.execute( request );
InputStream inputStream = AndroidHttpClient.getUngzippedContent( response.getEntity() );
Volker Neumann
fuente
Buen consejo el modifiedRequest & getUngzipped, también, necesitaba copiar EntityUtils.toString (HttpEntity) para analizar la secuencia ungzipeed como String
Marcos Vasconcelos
1
AndroidHttpClient quedó obsoleto en el nivel de API 22.
Alex Kucherenko
13

Creo que la muestra de código en este enlace es más interesante: ClientGZipContentCompression.java

Ellos están usando HttpRequestInterceptor y HttpResponseInterceptor

Muestra por solicitud:

        httpclient.addRequestInterceptor(new HttpRequestInterceptor() {

            public void process(
                    final HttpRequest request,
                    final HttpContext context) throws HttpException, IOException {
                if (!request.containsHeader("Accept-Encoding")) {
                    request.addHeader("Accept-Encoding", "gzip");
                }
            }

        });

Muestra por respuesta:

        httpclient.addResponseInterceptor(new HttpResponseInterceptor() {

            public void process(
                    final HttpResponse response,
                    final HttpContext context) throws HttpException, IOException {
                HttpEntity entity = response.getEntity();
                Header ceheader = entity.getContentEncoding();
                if (ceheader != null) {
                    HeaderElement[] codecs = ceheader.getElements();
                    for (int i = 0; i < codecs.length; i++) {
                        if (codecs[i].getName().equalsIgnoreCase("gzip")) {
                            response.setEntity(
                                    new GzipDecompressingEntity(response.getEntity()));
                            return;
                        }
                    }
                }
            }

        });
Niqo
fuente
1
¿Alguna razón por la que te parece más interesante?
Gaurav Agarwal
3
@codingcrow Esto es lo que está buscando: en este caso particular, el cliente HTTP tiene la capacidad de compresión GZIP de contenido transparente al agregar dos interceptores de protocolo: un interceptor de solicitudes que agrega el encabezado 'Accept-Encoding: gzip' a todas las solicitudes salientes y una respuesta interceptor que expande automáticamente las entidades de respuesta comprimidas envolviéndolas con una clase decoradora descomprimida. El uso de interceptores de protocolo hace que la compresión de contenido sea completamente transparente para el consumidor de la interfaz HttpClient.
clauziere
Fuente
clauziere
GzipDecompressingEntity no se puede encontrar en android.jar (2.2)
imcaptor
1

No he usado GZip, pero supongo que debería usar el flujo de entrada de su HttpURLConnectiono HttpResponsecomo GZIPInputStream, y no otra clase específica.

Dimitar Dimitrov
fuente
HTTPURLConnection tiene gzip activado de forma predeterminada. Solo necesita asegurarse de que su servidor web pueda devolver páginas gzip. developer.android.com/reference/java/net/HttpURLConnection.html Pude devolver páginas gzip desde php usando ob_start ("ob_gzhandler");
metric152
¡No responda si no tiene una respuesta!
Martin.Martinsson
0

En mi caso fue así:

URLConnection conn = ...;
InputStream instream = conn.getInputStream();
String encodingHeader = conn.getHeaderField("Content-Encoding");
if (encodingHeader != null && encodingHeader.toLowerCase().contains("gzip"))
{
    instream = new GZIPInputStream(instream);
}
Kospol
fuente