Android: Giao tiếp HTTP nên sử dụng “Mã hóa chấp nhận: gzip”


109

Tôi có một giao tiếp HTTP tới một máy chủ web yêu cầu dữ liệu JSON. Tôi muốn nén luồng dữ liệu này với Content-Encoding: gzip. Có cách nào tôi có thể đặt Accept-Encoding: gziptrong HttpClient của mình không? Tìm kiếm gziptrong Android References không hiển thị bất kỳ thứ gì liên quan đến HTTP, như bạn có thể thấy ở đây .


1
Android-WebRequest hỗ trợ GZIP và phản hồi không nén tự động, ví dụ: với new WebRequest().get().to("http://www.example.com/").askForGzip(true).executeSync(). Cụ thể, phương thức parseResponse (...) sẽ là những gì bạn đang tìm kiếm.
caw

Câu trả lời:


174

Bạn nên sử dụng tiêu đề http để cho biết một kết nối có thể chấp nhận dữ liệu được mã hóa gzip, ví dụ:

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

Kiểm tra phản hồi để mã hóa nội dung:

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

7
Đó là một câu trả lời tuyệt vời và rất hữu ích với tất cả các chi tiết tôi cần. Cảm ơn rất nhiều. Một nhận xét: thay vì addHeader, tôi đã sử dụng setHeader. Theo những gì tôi hiểu, điều này sẽ ghi đè "Chấp nhận-Mã hóa" hiện có nếu có. Không chắc cách tiếp cận nào là đúng / tốt hơn. Ghi đè tiêu đề hiện có để đảm bảo nó có giá trị phù hợp hoặc thêm nó trong trường hợp có thể có các tiêu đề Chấp nhận-Mã hóa khác song song.
znq

Sau đó, bạn đặt instream ở đâu?
Mikey

7
điều này không gzip yêu cầu, nó chỉ cho máy chủ biết rằng bạn có thể chấp nhận phản hồi gzip'd.
Jeffrey Blattman

1
Đối với bất kỳ ai cũng gặp khó khăn khi thiết lập và chạy các dịch vụ của google, đây là hai vấn đề mà tôi đã mất khá nhiều thời gian để tìm hiểu: (1) một số dịch vụ của google yêu cầu chuỗi tác nhân người dùng do khách hàng cung cấp phải chứa chuỗi gzipđể thực sự kích hoạt nén gzip. (2) hãy nhớ rằng máy chủ có thể không gzip phản hồi nếu nó quá nhỏ ...
sven

Vấn đề của tôi là tiêu đề gzip không được nhìn thấy. Tôi đang sử dụng Wireshark để đánh hơi mạng ở phía máy chủ và tôi không thấy dấu vết của tiêu đề "gzip" mà tôi đã thêm vào trong android ...
Ted

33

Nếu bạn đang sử dụng API cấp 8 trở lên thì có AndroidHttpClient .

Nó có các phương thức trợ giúp như:

public static InputStream getUngzippedContent (HttpEntity entity)

public static void modifyRequestToAcceptGzipResponse (HttpRequest request)

dẫn đến mã ngắn gọn hơn nhiều:

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

Đẹp tip modifyRequest & getUngzipped, cũng được, tôi cần phải sao chép EntityUtils.toString (HttpEntity) để phân tích dòng ungzipeed như String
Marcos Vasconcelos

1
AndroidHttpClient không được dùng nữa trong API cấp 22.
Alex Kucherenko

13

Tôi nghĩ mẫu mã tại liên kết này thú vị hơn: ClientGZipContentCompression.java

Họ đang sử dụng HttpRequestInterceptorHttpResponseInterceptor

Mẫu cho yêu cầu:

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

        });

Mẫu cho câu trả lời:

        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
Bất kỳ lý do tại sao bạn nghĩ rằng nó là thú vị hơn?
Gaurav Agarwal,

3
@codingcrow Đây là những gì bạn đang tìm kiếm: Trong trường hợp cụ thể này, ứng dụng khách HTTP có khả năng nén GZIP nội dung minh bạch bằng cách thêm hai bộ chặn giao thức: bộ đánh chặn yêu cầu thêm tiêu đề 'Chấp nhận mã hóa: gzip' cho tất cả các yêu cầu gửi đi và phản hồi interceptor tự động mở rộng các thực thể phản hồi đã nén bằng cách bọc chúng bằng một lớp decorator không nén. Việc sử dụng các bộ chặn giao thức làm cho việc nén nội dung hoàn toàn trong suốt đối với người tiêu dùng giao diện HttpClient.
clauziere 3/12/12


GzipDecompressingEntity không thể được tìm thấy trong android.jar (2.2)
imcaptor

1

Tôi đã không được sử dụng Gzip, nhưng tôi sẽ cho rằng bạn nên sử dụng các dòng đầu vào từ bạn HttpURLConnectionhoặc HttpResponseGZIPInputStream, chứ không phải một số lớp khác cụ thể.


HTTPURLConnection đã bật gzip theo mặc định. Bạn chỉ cần đảm bảo máy chủ web của mình có thể trả về các trang gzip. developer.android.com/reference/java/net/HttpURLConnection.html Tôi có thể trả lại các trang gzip từ php bằng cách sử dụng ob_start ("ob_gzhandler");
metric152

Đừng trả lời khi bạn không có câu trả lời!
Martin.Martinsson

0

Trong trường hợp của tôi, nó như thế này:

URLConnection conn = ...;
InputStream instream = conn.getInputStream();
String encodingHeader = conn.getHeaderField("Content-Encoding");
if (encodingHeader != null && encodingHeader.toLowerCase().contains("gzip"))
{
    instream = new GZIPInputStream(instream);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.