天天看點

Okhttp3請求網絡開啟Gzip壓縮前言方案後記

前言

首先OkHttp3是支援Gzip解壓縮的,不過我們要明白,它是支援我們在發起請求的時候自動加入header,

Accept-Encoding: gzip

,而我們的伺服器傳回的時候header中有

Content-Encoding: gzip

關于更多深入的内容呢,可以參考閱讀下面這篇文章,講的非常好!

聊聊HTTP gzip壓縮與常見的Android網絡架構

那麼,我們在向伺服器送出大量資料的時候,希望對post的資料進行gzip壓縮,改怎麼辦?

下邊給出方案!

方案

官方采用的是自定義攔截器的方式!

源碼在:

okhttp/samples/guide/src/main/java/okhttp3/recipes/RequestBodyCompression.java

廢話不多說,直接上代碼:

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.BufferedSink;
import okio.GzipSink;
import okio.Okio;

public class GzipRequestInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
            return chain.proceed(originalRequest);
        }

        Request compressedRequest = originalRequest.newBuilder()
                .header("Content-Encoding", "gzip")
                .method(originalRequest.method(), gzip(originalRequest.body()))
                .build();
        return chain.proceed(compressedRequest);
    }

    private RequestBody gzip(final RequestBody body) {
        return new RequestBody() {
            @Override
            public MediaType contentType() {
                return body.contentType();
            }

            @Override
            public long contentLength() {
                return -; // 無法提前知道壓縮後的資料大小
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
                body.writeTo(gzipSink);
                gzipSink.close();
            }
        };
    }
}
           

然後建構OkhttpClient的時候,添加攔截器:

OkHttpClient okHttpClient = new OkHttpClient.Builder() 
    .addInterceptor(new GzipRequestInterceptor())//開啟Gzip壓縮
    ...
    .build();
           

後記

如果需要帶有内容長度content-length的,可以檢視這個issue:

Here’s the full gzip interceptor with content length, to whom it may concern:

繼續閱讀