Android: la comunicazione HTTP deve utilizzare "Accept-Encoding: gzip"


109

Ho una comunicazione HTTP con un server web che richiede dati JSON. Vorrei comprimere questo flusso di dati con Content-Encoding: gzip. C'è un modo per impostare Accept-Encoding: gzipnel mio HttpClient? La ricerca gzipnei riferimenti Android non mostra nulla relativo a HTTP, come puoi vedere qui .


1
Android-WebRequest supporta GZIP e le risposte non compresse automaticamente, ad esempio con new WebRequest().get().to("http://www.example.com/").askForGzip(true).executeSync(). In particolare, il metodo parseResponse (...) dovrebbe essere quello che stai cercando.
caw

Risposte:


174

È necessario utilizzare le intestazioni http per indicare che una connessione può accettare dati codificati in gzip, ad esempio:

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

Controlla la risposta per la codifica del contenuto:

InputStream instream = response.getEntity().getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
    instream = new GZIPInputStream(instream);
}

7
Questa è un'ottima risposta e molto utile con tutti i dettagli di cui avevo bisogno. Molte grazie. Un commento: invece di addHeader ho usato setHeader. Da quello che ho capito, questo sovrascrive la "Accept-Encoding" esistente se ce n'è una. Non sono sicuro di quale sia l'approccio giusto / migliore. Per sovrascrivere un'intestazione esistente per assicurarsi che abbia il valore corretto o per aggiungerla nel caso in cui possano esserci altre intestazioni Accept-Encoding in parallelo.
znq

dove metti l'istream allora?
Mikey

7
questo non gzip la richiesta, dice solo al server che puoi accettare una risposta gzip.
Jeffrey Blattman

1
Per chiunque abbia anche problemi a farlo funzionare per i servizi di Google, ecco due problemi che mi ci è voluto un po 'di tempo per scoprirlo: (1) alcuni servizi di Google richiedono che la stringa dell'agente utente fornita dal client contenga la stringa gzipper abilitarsi davvero compressione gzip. (2) tieni presente che il server potrebbe non comprimere la risposta se è troppo piccola ...
sven

Il mio problema è che l'intestazione gzip non si vede da nessuna parte. Sto usando Wireshark per annusare la rete sul lato server e non vedo traccia dell'intestazione "gzip" che ho aggiunto in Android ...
Ted

33

Se utilizzi il livello API 8 o superiore, c'è AndroidHttpClient .

Ha metodi di supporto come:

public static InputStream getUngzippedContent (HttpEntity entity)

e

public static void modifyRequestToAcceptGzipResponse (HttpRequest request)

portando a un codice molto più succinto:

AndroidHttpClient.modifyRequestToAcceptGzipResponse( request );
HttpResponse response = client.execute( request );
InputStream inputStream = AndroidHttpClient.getUngzippedContent( response.getEntity() );

Bel suggerimento il modifyRequest e getUngzipped, inoltre, avevo bisogno di copiare EntityUtils.toString (HttpEntity) per analizzare il flusso ungzipeed come String
Marcos Vasconcelos

1
AndroidHttpClient è stato deprecato nel livello API 22.
Alex Kucherenko

13

Penso che l'esempio di codice a questo link sia più interessante: ClientGZipContentCompression.java

Stanno usando HttpRequestInterceptor e HttpResponseInterceptor

Campione per richiesta:

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

        });

Esempio per la risposta:

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

        });

1
Qualche motivo per cui pensi che sia più interessante?
Gaurav Agarwal

3
@codingcrow Ecco cosa stai cercando: in questo caso particolare il client HTTP è in grado di comprimere GZIP di contenuti trasparenti aggiungendo due intercettori di protocollo: un intercettore di richieste che aggiunge l'intestazione 'Accept-Encoding: gzip' a tutte le richieste in uscita e una risposta interceptor che espande automaticamente le entità di risposta compresse avvolgendole in una classe decorator non comprimibile. L'utilizzo di intercettori di protocollo rende la compressione del contenuto completamente trasparente per il consumatore dell'interfaccia HttpClient.
clauziere


GzipDecompressingEntity non può essere trovato in android.jar (2.2)
imcaptor

1

Non ho usato GZip, ma presumo che dovresti usare il flusso di input dal tuo HttpURLConnectiono HttpResponseas GZIPInputStream, e non qualche altra specifica classe.


HTTPURLConnection ha gzip attivato per impostazione predefinita. Devi solo assicurarti che il tuo server web possa restituire pagine gzip. developer.android.com/reference/java/net/HttpURLConnection.html Sono stato in grado di restituire pagine gzip da php utilizzando ob_start ("ob_gzhandler");
metric152

Non rispondere quando non hai una risposta!
Martin.Martinsson

0

Nel mio caso è stato così:

URLConnection conn = ...;
InputStream instream = conn.getInputStream();
String encodingHeader = conn.getHeaderField("Content-Encoding");
if (encodingHeader != null && encodingHeader.toLowerCase().contains("gzip"))
{
    instream = new GZIPInputStream(instream);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.