Android: la communication HTTP doit utiliser "Accept-Encoding: gzip"

109

J'ai une communication HTTP avec un serveur Web demandant des données JSON. Je voudrais compresser ce flux de données avec Content-Encoding: gzip. Existe-t-il un moyen de définir Accept-Encoding: gzipdans mon HttpClient? La recherche gzipdans les références Android n'affiche rien en rapport avec HTTP, comme vous pouvez le voir ici .

znq
la source
1
Android-WebRequest prend en charge GZIP et les réponses non compressées automatiquement, par exemple avec new WebRequest().get().to("http://www.example.com/").askForGzip(true).executeSync(). Plus précisément, la méthode parseResponse (...) devrait être ce que vous recherchez.
caw

Réponses:

174

Vous devez utiliser des en-têtes http pour indiquer qu'une connexion peut accepter des données codées gzip, par exemple:

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

Vérifiez la réponse pour l'encodage du contenu:

InputStream instream = response.getEntity().getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
    instream = new GZIPInputStream(instream);
}
Bakhtiyor
la source
7
C'est une réponse formidable et très utile avec tous les détails dont j'avais besoin. Merci beaucoup. Un commentaire: au lieu d'addHeader, j'ai utilisé setHeader. D'après ce que je comprends, cela remplace le "Accept-Encoding" existant s'il y en a un. Je ne sais pas quelle approche est la bonne / la meilleure. Pour écraser un en-tête existant pour s'assurer qu'il a la bonne valeur, ou pour l'ajouter au cas où il pourrait y avoir d'autres en-têtes Accept-Encoding en parallèle.
znq
où mettez-vous alors l'instream?
Mikey
7
cela ne gzip pas la requête, cela indique seulement au serveur que vous pouvez accepter une réponse gzip.
Jeffrey Blattman
1
Pour tous ceux qui ont également du mal à le faire fonctionner pour les services Google, voici deux problèmes qui m'ont pris un certain temps à découvrir: (1) certains services Google nécessitent que la chaîne d'agent utilisateur fournie par le client contienne la chaîne gzippour vraiment activer compression gzip. (2) gardez à l'esprit que le serveur peut ne pas gzip la réponse si elle est trop petite ...
sven
Mon problème est que l'en-tête gzip est introuvable. J'utilise Wireshark pour renifler le réseau côté serveur, et je ne vois aucune trace de l'en-tête "gzip" que j'ai ajouté dans Android ...
Ted
33

Si vous utilisez le niveau d'API 8 ou supérieur, il y a AndroidHttpClient .

Il a des méthodes d'aide comme:

public static InputStream getUngzippedContent (HttpEntity entity)

et

public static void modifyRequestToAcceptGzipResponse (HttpRequest request)

conduisant à un code beaucoup plus succinct:

AndroidHttpClient.modifyRequestToAcceptGzipResponse( request );
HttpResponse response = client.execute( request );
InputStream inputStream = AndroidHttpClient.getUngzippedContent( response.getEntity() );
Volker Neumann
la source
Bonne astuce le modifyRequest & getUngzipped, aussi, j'avais besoin de copier EntityUtils.toString (HttpEntity) pour analyser le flux ungzipeed comme String
Marcos Vasconcelos
1
AndroidHttpClient est obsolète au niveau de l'API 22.
Alex Kucherenko
13

Je pense que l'exemple de code sur ce lien est plus intéressant: ClientGZipContentCompression.java

Ils utilisent HttpRequestInterceptor et HttpResponseInterceptor

Échantillon pour demande:

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

        });

Exemple de réponse:

        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
la source
1
Une raison pour laquelle vous pensez que c'est plus intéressant?
Gaurav Agarwal
3
@codingcrow Voici ce que vous recherchez: Dans ce cas particulier, le client HTTP est rendu capable de compression GZIP de contenu transparent en ajoutant deux intercepteurs de protocole: un intercepteur de demande qui ajoute l'en-tête `` Accept-Encoding: gzip '' à toutes les demandes sortantes et une réponse intercepteur qui développe automatiquement les entités de réponse compressées en les enveloppant avec une classe de décorateur de décompression. L'utilisation d'intercepteurs de protocole rend la compression de contenu complètement transparente pour le consommateur de l'interface HttpClient.
clauziere
Source
clauziere
GzipDecompressingEntity ne peut pas être trouvé dans android.jar (2.2)
imcaptor
1

Je n'ai pas utilisé GZip, mais je suppose que vous devriez utiliser le flux d'entrée de votre HttpURLConnectionou HttpResponseas GZIPInputStream, et non d'une autre classe spécifique.

Dimitar Dimitrov
la source
HTTPURLConnection a gzip activé par défaut. Vous devez juste vous assurer que votre serveur Web peut renvoyer des pages gzip. developer.android.com/reference/java/net/HttpURLConnection.html J'ai pu renvoyer des pages gzip depuis php en utilisant ob_start ("ob_gzhandler");
metric152
Ne répondez pas lorsque vous n'avez pas de réponse!
Martin.Martinsson
0

Dans mon cas, c'était comme ça:

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