Android: การสื่อสาร HTTP ควรใช้“ Accept-Encoding: gzip”


109

ฉันมีการสื่อสาร HTTP ไปยังเว็บเซิร์ฟเวอร์ที่ขอข้อมูล JSON Content-Encoding: gzipฉันต้องการบีบอัดกระแสข้อมูลนี้กับ มีวิธีตั้งค่าAccept-Encoding: gzipใน HttpClient หรือไม่? ค้นหาgzipในการอ้างอิง Android ไม่แสดงอะไรที่เกี่ยวข้องกับ HTTP, ที่คุณสามารถดูที่นี่


1
Android-WebRequestรองรับ GZIP และการตอบสนองที่ไม่มีการบีบอัดโดยอัตโนมัติเช่นกับnew WebRequest().get().to("http://www.example.com/").askForGzip(true).executeSync()ไฟล์. โดยเฉพาะเมธอดparseResponse (... )ควรเป็นสิ่งที่คุณกำลังมองหา
caw

คำตอบ:


174

คุณควรใช้ส่วนหัว http เพื่อระบุว่าการเชื่อมต่อสามารถรับข้อมูลที่เข้ารหัส gzip ได้เช่น:

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

ตรวจสอบการตอบสนองสำหรับการเข้ารหัสเนื้อหา:

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

7
นั่นเป็นคำตอบที่ยอดเยี่ยมและเป็นประโยชน์มากพร้อมรายละเอียดทั้งหมดที่ฉันต้องการ ขอบคุณมาก. ความคิดเห็นหนึ่ง: แทนที่จะใช้ addHeader ฉันใช้ setHeader จากสิ่งที่ฉันเข้าใจสิ่งนี้จะแทนที่ "Accept-Encoding" ที่มีอยู่หากมี ไม่แน่ใจว่าแนวทางใดเหมาะสม / ดีกว่า ในการเขียนทับส่วนหัวที่มีอยู่เพื่อให้แน่ใจว่ามีค่าที่ถูกต้องหรือเพิ่มในกรณีที่สามารถมีส่วนหัว Accept-Encoding อื่น ๆ ควบคู่กันได้
znq

แล้วคุณจะใส่ในสตรีมไว้ที่ไหน
กี้

7
สิ่งนี้ไม่ได้ gzip คำขอ แต่จะบอกเซิร์ฟเวอร์ว่าคุณสามารถยอมรับการตอบกลับ gzip'd เท่านั้น
Jeffrey Blattman

1
สำหรับใครก็ตามที่มีปัญหาในการเริ่มต้นใช้งานบริการของ Google นี่คือปัญหาสองประการที่ทำให้ฉันใช้เวลาพอสมควรในการค้นหา: (1) บริการของ Google บางอย่างต้องการสตริงตัวแทนผู้ใช้ที่ไคลเอ็นต์ให้มาเพื่อให้มีสตริงgzipเพื่อเปิดใช้งานจริงๆการบีบอัด gzip (2) โปรดทราบว่าเซิร์ฟเวอร์อาจไม่ gzip การตอบสนองหากมีขนาดเล็กเกินไป ...
เวน

ปัญหาของฉันคือส่วนหัว gzip ไม่มีให้เห็น ฉันใช้ Wireshark เพื่อดักจับเครือข่ายที่ฝั่งเซิร์ฟเวอร์และฉันไม่เห็นส่วนหัว "gzip" ที่ฉันเพิ่มใน Android ...
Ted

33

หากคุณกำลังใช้ระดับ API 8 หรือสูงกว่ามีAndroidHttpClient

มีวิธีการช่วยเหลือเช่น:

public static InputStream getUngzippedContent (HttpEntity entity)

และ

public static void modifyRequestToAcceptGzipResponse (HttpRequest request)

นำไปสู่รหัสที่รวบรัดมากขึ้น:

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

เคล็ดลับที่ดีในการแก้ไขขอ & getUngzipped เช่นกันฉันต้องคัดลอก EntityUtils.toString (HttpEntity) เพื่อแยกวิเคราะห์สตรีมที่ไม่มีการบีบอัดเป็น String
Marcos Vasconcelos

1
AndroidHttpClient เลิกใช้งานแล้วใน API ระดับ 22
Alex Kucherenko

13

ฉันคิดว่าตัวอย่างโค้ดในลิงค์นี้น่าสนใจกว่า: ClientGZipContentCompression.java

พวกเขากำลังใช้HttpRequestInterceptorและHttpResponseInterceptor

ตัวอย่างสำหรับการร้องขอ:

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

        });

ตัวอย่างสำหรับคำตอบ:

        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
เหตุผลใดที่คุณคิดว่ามันน่าสนใจกว่านี้?
Gaurav Agarwal

3
@codingcrow นี่คือสิ่งที่คุณกำลังมองหา: ในกรณีนี้ไคลเอนต์ HTTP นั้นมีความสามารถในการบีบอัดเนื้อหา GZIP แบบโปร่งใสโดยการเพิ่มตัวดักโปรโตคอลสองตัว: ตัวสกัดกั้นคำขอที่เพิ่มส่วนหัว 'Accept-Encoding: gzip' ในคำขอส่งออกทั้งหมดและการตอบกลับ interceptor ที่ขยายเอนทิตีการตอบสนองที่ถูกบีบอัดโดยอัตโนมัติโดยการรวมเข้ากับคลาสมัณฑนากรที่ไม่บีบอัด การใช้ตัวสกัดกั้นโปรโตคอลทำให้การบีบอัดเนื้อหาโปร่งใสอย่างสมบูรณ์สำหรับผู้ใช้อินเทอร์เฟซ HttpClient
clauziere


GzipDecompressingEntity ไม่พบใน android.jar (2.2)
imcaptor

1

ฉันไม่ได้ใช้ GZip แต่ฉันคิดว่าคุณควรใช้สตรีมอินพุตจากHttpURLConnectionหรือHttpResponseเป็นของคุณGZIPInputStreamไม่ใช่คลาสอื่นที่เฉพาะเจาะจง


HTTPURLConnection ได้เปิด gzip ไว้โดยค่าเริ่มต้น คุณต้องแน่ใจว่าเว็บเซิร์ฟเวอร์ของคุณสามารถส่งคืนเพจ gzip ได้ developer.android.com/reference/java/net/HttpURLConnection.html ฉันสามารถคืนหน้า gzip จาก php โดยใช้ ob_start ("ob_gzhandler");
metric152

อย่าตอบเมื่อไม่มีคำตอบ!
Martin Martinsson

0

ในกรณีของฉันมันเป็นเช่นนี้:

URLConnection conn = ...;
InputStream instream = conn.getInputStream();
String encodingHeader = conn.getHeaderField("Content-Encoding");
if (encodingHeader != null && encodingHeader.toLowerCase().contains("gzip"))
{
    instream = new GZIPInputStream(instream);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.