Android: a comunicação HTTP deve usar “Accept-Encoding: gzip”

109

Tenho uma comunicação HTTP para um servidor da web solicitando dados JSON. Eu gostaria de compactar esse fluxo de dados com Content-Encoding: gzip. Existe uma maneira de definir Accept-Encoding: gzipem meu HttpClient? A busca por gzipnas Referências do Android não mostra nada relacionado a HTTP, como você pode ver aqui .

znq
fonte
1
Android-WebRequest suporta GZIP e respostas descompactadas automaticamente, por exemplo, com new WebRequest().get().to("http://www.example.com/").askForGzip(true).executeSync(). Especificamente, o método parseResponse (...) deve ser o que você está procurando.
caw

Respostas:

174

Você deve usar cabeçalhos http para indicar que uma conexão pode aceitar dados codificados por gzip, por exemplo:

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

Verifique a resposta para codificação de conteúdo:

InputStream instream = response.getEntity().getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
    instream = new GZIPInputStream(instream);
}
Bakhtiyor
fonte
7
Essa é uma resposta ótima e muito útil com todos os detalhes de que eu precisava. Muito obrigado. Um comentário: em vez de addHeader, usei setHeader. Pelo que entendi, isso sobrescreve o "Aceitar-Codificação" existente, se houver. Não tenho certeza de qual abordagem é a certa / melhor. Para sobrescrever um cabeçalho existente para ter certeza de que tem o valor correto ou para adicioná-lo no caso de haver outros cabeçalhos Accept-Encoding em paralelo.
znq
onde você coloca o instream então?
Mikey
7
isso não gzip a solicitação, apenas informa ao servidor que você pode aceitar uma resposta gzip.
Jeffrey Blattman
1
Para qualquer um que também esteja tendo problemas para colocá-lo em funcionamento para os serviços do Google, aqui estão dois problemas que levei algum tempo para descobrir: (1) alguns serviços do Google exigem que a string do agente do usuário fornecida pelo cliente contenha a string gzippara realmente ativar Compressão gzip. (2) lembre-se de que o servidor pode não fazer o gzip da resposta se for muito pequena ...
sven
Meu problema é que o cabeçalho gzip está longe de ser visto. Estou usando o Wireshark para farejar a rede no lado do servidor e não vejo nenhum traço do cabeçalho "gzip" que adicionei no android ...
Ted de
33

Se você estiver usando a API de nível 8 ou superior, há AndroidHttpClient .

Possui métodos auxiliares como:

public static InputStream getUngzippedContent (HttpEntity entity)

e

public static void modifyRequestToAcceptGzipResponse (HttpRequest request)

levando a um código muito mais sucinto:

AndroidHttpClient.modifyRequestToAcceptGzipResponse( request );
HttpResponse response = client.execute( request );
InputStream inputStream = AndroidHttpClient.getUngzippedContent( response.getEntity() );
Volker Neumann
fonte
Boa dica para modifyRequest & getUngzipped, também, eu precisei copiar EntityUtils.toString (HttpEntity) para analisar o fluxo ungzipeed como String
Marcos Vasconcelos
1
AndroidHttpClient ficou obsoleto na API de nível 22.
Alex Kucherenko,
13

Acho que a amostra de código neste link é mais interessante: ClientGZipContentCompression.java

Eles estão usando HttpRequestInterceptor e HttpResponseInterceptor

Amostra para solicitação:

        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");
                }
            }

        });

Amostra para resposta:

        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
fonte
1
Alguma razão pela qual você acha que é mais interessante?
Gaurav Agarwal
3
@codingcrow Aqui está o que você está procurando: neste caso particular, o cliente HTTP tornou-se capaz de compactação GZIP de conteúdo transparente adicionando dois interceptores de protocolo: um interceptor de solicitação que adiciona o cabeçalho 'Accept-Encoding: gzip' a todas as solicitações de saída e uma resposta interceptor que expande automaticamente entidades de resposta compactadas envolvendo-as com uma classe de decorador descompactante. O uso de interceptores de protocolo torna a compactação de conteúdo completamente transparente para o consumidor da interface HttpClient.
clauziere
Fonte
clauziere
GzipDecompressingEntity não pode ser encontrado em android.jar (2.2)
imcaptor
1

Eu não usei o GZip, mas presumo que você deva usar o fluxo de entrada de seu HttpURLConnectionou HttpResponseas GZIPInputStream, e não alguma outra classe específica.

Dimitar Dimitrov
fonte
HTTPURLConnection tem gzip ativado por padrão. Você só precisa ter certeza de que seu servidor da web pode retornar páginas gzip. developer.android.com/reference/java/net/HttpURLConnection.html Consegui retornar páginas gzip do php usando ob_start ("ob_gzhandler");
metric152
Não responda quando você não tem uma resposta!
Martin.Martinsson
0

No meu caso foi assim:

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