Android: Die HTTP-Kommunikation sollte "Accept-Encoding: gzip" verwenden.

109

Ich habe eine HTTP-Kommunikation mit einem Webserver, der JSON-Daten anfordert. Ich möchte diesen Datenstrom mit komprimieren Content-Encoding: gzip. Gibt es eine Möglichkeit, die ich Accept-Encoding: gzipin meinem HttpClient festlegen kann ? Die Suche gzipin den Android-Referenzen zeigt nichts im Zusammenhang mit HTTP an, wie Sie hier sehen können .

znq
quelle
1
Android-WebRequest unterstützt GZIP und unkomprimierte Antworten automatisch, z new WebRequest().get().to("http://www.example.com/").askForGzip(true).executeSync(). B. mit . Insbesondere sollte die Methode parseResponse (...) genau das sein, wonach Sie suchen.
Caw

Antworten:

174

Sie sollten http-Header verwenden, um anzugeben, dass eine Verbindung gzip-codierte Daten akzeptieren kann, z.

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

Überprüfen Sie die Antwort auf Inhaltskodierung:

InputStream instream = response.getEntity().getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
    instream = new GZIPInputStream(instream);
}
Bakhtiyor
quelle
7
Das ist eine großartige und sehr hilfreiche Antwort mit allen Details, die ich brauchte. Vielen Dank. Ein Kommentar: Anstelle von addHeader habe ich setHeader verwendet. Soweit ich weiß, überschreibt dies die vorhandene "Accept-Encoding", falls es eine gibt. Ich bin mir nicht sicher, welcher Ansatz der richtige / bessere ist. Um einen vorhandenen Header zu überschreiben, um sicherzustellen, dass er den richtigen Wert hat, oder um ihn hinzuzufügen, falls parallel andere Accept-Encoding-Header vorhanden sein können.
ZnQ
Wo legst du dann den Instream hin?
Mikey
7
Dadurch wird die Anforderung nicht gzip, sondern nur dem Server mitgeteilt, dass Sie eine gzip-Antwort akzeptieren können.
Jeffrey Blattman
1
Für alle, die auch Probleme haben, dies für Google-Dienste zum Laufen zu bringen, gab es zwei Probleme, die ich einige Zeit in Anspruch genommen habe: (1) Bei einigen Google-Diensten muss die vom Client bereitgestellte Benutzeragentenzeichenfolge die Zeichenfolge enthalten gzip, damit sie wirklich aktiviert werden kann gzip-Komprimierung. (2) Denken Sie daran, dass der Server die Antwort möglicherweise nicht komprimiert, wenn sie zu klein ist ...
am
Mein Problem ist, dass der gzip-Header nirgends zu sehen ist. Ich benutze Wireshark, um das Netzwerk auf der Serverseite zu schnüffeln, und ich sehe keine Spur des "gzip" -Headers, den ich in Android hinzugefügt habe ...
Ted
33

Wenn Sie API Level 8 oder höher verwenden, gibt es AndroidHttpClient .

Es hat Hilfsmethoden wie:

public static InputStream getUngzippedContent (HttpEntity entity)

und

public static void modifyRequestToAcceptGzipResponse (HttpRequest request)

was zu einem viel prägnanteren Code führt:

AndroidHttpClient.modifyRequestToAcceptGzipResponse( request );
HttpResponse response = client.execute( request );
InputStream inputStream = AndroidHttpClient.getUngzippedContent( response.getEntity() );
Volker Neumann
quelle
Netter Tipp, die modifyRequest & getUngzipped, außerdem musste ich EntityUtils.toString (HttpEntity) kopieren, um den ungipften Stream als String zu analysieren
Marcos Vasconcelos
1
AndroidHttpClient war in API Level 22 veraltet.
Alex Kucherenko
13

Ich denke, das Codebeispiel unter diesem Link ist interessanter: ClientGZipContentCompression.java

Sie verwenden HttpRequestInterceptor und HttpResponseInterceptor

Beispiel für Anfrage:

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

        });

Beispiel für eine Antwort:

        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
quelle
1
Gibt es einen Grund, warum Sie es interessanter finden?
Gaurav Agarwal
3
@codingcrow Folgendes suchen Sie: In diesem speziellen Fall wird der HTTP-Client durch Hinzufügen von zwei Protokoll-Interceptors zur transparenten GZIP-Komprimierung von Inhalten befähigt: einem Anforderungs-Interceptor, der allen ausgehenden Anforderungen den Header "Accept-Encoding: gzip" und eine Antwort hinzufügt Interceptor, der komprimierte Antwortentitäten automatisch erweitert, indem er sie mit einer dekomprimierenden Decorator-Klasse umschließt. Die Verwendung von Protokoll-Interceptors macht die Inhaltskomprimierung für den Verbraucher der HttpClient-Schnittstelle vollständig transparent.
Clauziere
Quelle
clauziere
GzipDecompressingEntity kann nicht in android.jar (2.2) gefunden werden
imcaptor
1

Ich habe GZip nicht verwendet, aber ich würde davon ausgehen, dass Sie den Eingabestream von Ihrer HttpURLConnectionoder HttpResponseals GZIPInputStreamund nicht eine bestimmte andere Klasse verwenden sollten.

Dimitar Dimitrov
quelle
Bei HTTPURLConnection ist gzip standardmäßig aktiviert. Sie müssen nur sicherstellen, dass Ihr Webserver gzip-Seiten zurückgeben kann. developer.android.com/reference/java/net/HttpURLConnection.html Ich konnte gzip-Seiten mit ob_start ("ob_gzhandler") von PHP zurückgeben.
Metric152
Antworte nicht, wenn du keine Antwort hast!
Martin.Martinsson
0

In meinem Fall war es so:

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