Android: Komunikasi HTTP harus menggunakan "Terima-Encoding: gzip"

109

Saya memiliki komunikasi HTTP ke server web yang meminta data JSON. Saya ingin mengompres aliran data ini dengan Content-Encoding: gzip. Apakah ada cara yang dapat saya atur Accept-Encoding: gzipdi HttpClient saya? Pencarian gzipdi Referensi Android tidak menunjukkan apapun yang berhubungan dengan HTTP, seperti yang Anda lihat di sini .

znq
sumber
1
Android-WebRequest mendukung GZIP dan respons yang tidak dikompresi secara otomatis, misalnya dengan new WebRequest().get().to("http://www.example.com/").askForGzip(true).executeSync(). Secara khusus, metode parseResponse (...) harus sesuai dengan yang Anda cari.
gak

Jawaban:

174

Anda harus menggunakan header http untuk menunjukkan bahwa koneksi dapat menerima data yang dikodekan gzip, misalnya:

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

Periksa tanggapan untuk pengkodean konten:

InputStream instream = response.getEntity().getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
    instream = new GZIPInputStream(instream);
}
Bakhtiyor
sumber
7
Itu adalah jawaban yang bagus dan sangat membantu dengan semua detail yang saya butuhkan. Terima kasih banyak. Satu komentar: alih-alih addHeader, saya menggunakan setHeader. Dari apa yang saya pahami, ini menimpa "Terima-Encoding" yang ada jika ada. Tidak yakin pendekatan mana yang benar / lebih baik. Untuk menimpa header yang ada untuk memastikannya memiliki nilai yang benar, atau untuk menambahkannya jika ada header Terima-Encoding lainnya secara paralel.
znq
di mana kamu meletakkan instream?
Mikey
7
ini tidak meng-gzip permintaan, ini hanya memberi tahu server bahwa Anda dapat menerima respons gzip.
Jeffrey Blattman
1
Bagi siapa pun yang juga mengalami kesulitan untuk mengaktifkan dan menjalankannya untuk layanan google, berikut adalah dua masalah yang membutuhkan waktu cukup lama bagi saya untuk mengetahuinya: (1) beberapa layanan google memerlukan string agen pengguna yang disediakan oleh klien untuk memuat string gzipagar benar - benar memungkinkan kompresi gzip. (2) perlu diingat bahwa server mungkin tidak meng-gzip respons jika terlalu kecil ...
sven
Masalah saya adalah bahwa header gzip tidak terlihat. Saya menggunakan Wireshark untuk mengendus jaringan di sisi server, dan saya tidak melihat jejak tajuk "gzip" yang saya tambahkan di android ...
Ted
33

Jika Anda menggunakan API level 8 atau lebih, ada AndroidHttpClient .

Ini memiliki metode pembantu seperti:

public static InputStream getUngzippedContent (HttpEntity entity)

dan

public static void modifyRequestToAcceptGzipResponse (HttpRequest request)

mengarah ke kode yang jauh lebih ringkas:

AndroidHttpClient.modifyRequestToAcceptGzipResponse( request );
HttpResponse response = client.execute( request );
InputStream inputStream = AndroidHttpClient.getUngzippedContent( response.getEntity() );
Volker Neumann
sumber
Tip bagus modifikRequest & getUngzipped, juga, saya perlu menyalin EntityUtils.toString (HttpEntity) untuk mengurai aliran ungzipeed sebagai String
Marcos Vasconcelos
1
AndroidHttpClient sudah tidak digunakan lagi di API level 22.
Alex Kucherenko
13

Saya pikir contoh kode di tautan ini lebih menarik: ClientGZipContentCompression.java

Mereka menggunakan HttpRequestInterceptor dan HttpResponseInterceptor

Sampel untuk permintaan:

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

        });

Contoh jawaban:

        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
sumber
1
Ada alasan mengapa menurut Anda itu lebih menarik?
Gaurav Agarwal
3
@codingcrow Inilah yang Anda cari: Dalam kasus khusus ini klien HTTP dibuat mampu konten transparan kompresi GZIP dengan menambahkan dua interseptor protokol: interseptor permintaan yang menambahkan header 'Terima-Encoding: gzip' ke semua permintaan keluar dan respons interceptor yang secara otomatis memperluas entitas respons terkompresi dengan membungkusnya dengan kelas dekorator yang tidak dikompresi. Penggunaan interseptor protokol membuat kompresi konten benar-benar transparan bagi pengguna antarmuka HttpClient.
clauziere
Sumber
clauziere
GzipDecompressingEntity tidak dapat ditemukan di android.jar (2.2)
imcaptor
1

Saya belum pernah menggunakan GZip, tetapi saya akan berasumsi bahwa Anda harus menggunakan aliran input dari Anda HttpURLConnectionatau HttpResponsesebagai GZIPInputStream, dan bukan beberapa kelas tertentu lainnya.

Dimitar Dimitrov
sumber
HTTPURLConnection mengaktifkan gzip secara default. Anda hanya perlu memastikan server web Anda dapat mengembalikan halaman gzip. developer.android.com/reference/java/net/HttpURLConnection.html Saya dapat mengembalikan halaman gzip dari php dengan menggunakan ob_start ("ob_gzhandler");
metric152
Jangan menjawab jika Anda tidak punya jawaban!
Martin.Martinsson
0

Dalam kasus saya, itu seperti ini:

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