2009-10-15 5 views
103

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. Y at-il un moyen que je peux définir Accept-Encoding: gzip dans mon HttpClient? La recherche de gzip dans les références Android ne montre pas tout ce qui concerne HTTP, comme vous pouvez le voir here.Android: la communication HTTP doit utiliser "Accept-Encoding: gzip"

+1

[Android-WebRequest] (https://github.com/delight-im/Android-WebRequest) prend en charge GZIP et les réponses non compressées automatiquement, par ex. avec 'new WebRequest(). get(). to (" http://www.example.com/ ") .askForGzip (true) .executeSync()'. Plus précisément, la méthode [parseResponse (...)] (https://github.com/delight-im/Android-WebRequest/blob/master/src/im/delight/android/webrequest/WebRequest.java) devrait être ce que vous cherchez. – caw

Répondre

168

Vous devez utiliser les en-têtes HTTP pour indiquer 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); 

réponse Vérifier l'encodage de contenu:

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

C'est une réponse géniale et très utile avec tous les détails dont j'avais besoin. Merci beaucoup. Un commentaire: au lieu de addHeader j'ai utilisé setHeader. D'après ce que je comprends, cela écrase le "Accept-Encoding" existant s'il y en a un. Je ne sais pas quelle approche est la bonne/meilleure. Pour remplacer 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

+0

où mettez-vous l'instream alors? – Mikey

+7

cela ne gzip la requête, il indique seulement le serveur que vous pouvez accepter une réponse gzip'd. –

2

Je n'ai pas utilisé GZip, mais je suppose que vous devez utiliser le flux d'entrée de votre HttpURLConnection ou HttpResponse comme GZIPInputStream, et non une autre classe spécifique.

+0

HTTPURLConnection a activé gzip par défaut. Vous devez juste vous assurer que votre serveur Web peut renvoyer des pages gzip. http://developer.android.com/reference/java/net/HttpURLConnection.html J'ai été capable de retourner des pages gzip à partir de php en utilisant ob_start ("ob_gzhandler"); – metric152

13

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

Ils utilisent HttpRequestInterceptor et HttpResponseInterceptor

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

     }); 
+1

Une raison pour laquelle vous pensez que c'est plus intéressant? –

+3

@codingcrow Voici ce que vous cherchez: _ Dans ce cas particulier, le client HTTP est capable de compression GZIP de contenu transparent en ajoutant deux intercepteurs de protocole: un intercepteur de requête qui ajoute l'en-tête Accept-Encoding: gzip à toutes les requêtes sortantes et un Intercepteur de réponse qui étend automatiquement les entités de réponse compressées en les enveloppant avec une classe de décorateur non compressée. L'utilisation d'intercepteurs de protocole rend la compression du contenu complètement transparente pour le consommateur de l'interface HttpClient. – clauziere

+0

[Source] (http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/ examples/client/ClientGZipContentCompression.java) – clauziere

33

Si vous utilisez le niveau API 8 ou au-dessus 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 succincte:

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

Nice tip the modifyRequest & getUngzipped, aussi, j'avais besoin de copier EntityUtils.toString (HttpEntity) pour analyser le flux ungzipeed en tant que chaîne –

+1

AndroidHttpClient était obsolète au niveau 22 de l'API. –

+0

J'ai passé environ une heure pour trouver la meilleure solution. C'est la meilleure réponse!!! Merci – shift66

0

Dans mon cas, il é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); 
} 
Questions connexes