Android - OKHttp:如何为POST启用gzip

时间:2017-12-04 16:10:30

标签: android nginx retrofit gzip okhttp

在我们的Android应用程序中,我将相当大的文件发送到我们的(NGINX)服务器,因此我希望将gzip用于我的Retrofit POST 消息。

有许多关于OkHttp的文档透明地使用gzip或更改标题以接受gzip(即在 GET 消息中)。

但是如何从我的设备中为发送gzip http POST消息启用此功能? 我是否必须写一个自定义的Intercepter或其他东西?或者只是在标题中添加一些东西?

2 个答案:

答案 0 :(得分:5)

根据以下recipe: gzip的正确流程是这样的:

OkHttpClient client = new OkHttpClient.Builder()
      .addInterceptor(new GzipRequestInterceptor())
      .build();

/** This interceptor compresses the HTTP request body. Many webservers can't handle this! */
  static 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 -1; // We don't know the compressed length in advance!
        }

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

答案 1 :(得分:-1)

除了已接受的答案:首先,声明此类(来自@Jason)

// to compress the body of request which is injected as interceptor.
public class GzipInterceptor implements Interceptor {
    @Override public okhttp3.Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();

        // do not set content encoding in negative use case

        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 -1; // We don't know the compressed length in advance!
            }

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

然后:

 //Encryption Interceptor
GzipInterceptor gzipInterceptor = new GzipInterceptor();

// OkHttpClient. Be conscious with the order
OkHttpClient okHttpClient = new OkHttpClient()
        .newBuilder()
        //httpLogging interceptor for logging network requests
        .addInterceptor(gzipInterceptor)
        .build();

最后将其作为客户添加到您的改造中:(无需进一步更改!)

 Retrofit retrofit = new Retrofit.Builder()
        .client(okHttpClient)
        .baseUrl(Constants.serveraddress)
        .addConverterFactory(GsonConverterFactory.create())
        .build();
Serverinterface serverinterface = retrofit.create(Serverinterface.class);