Android - OKHttp: how to enable gzip for POST

2020-06-23 07:57发布

问题:

In our Android App, I'm sending pretty large files to our (NGINX) server so I was hoping to use gzip for my Retrofit POST message.

There are many documentations about OkHttp using gzip transparently or changing the headers in order to accept gzip (i.e. in a GET message).

But how can I enable this feature for sending gzip http POST messages from my device? Do I have to write a custom Intercepter or something? Or simply add something to the headers?

回答1:

According to the following recipe: The correct flow for gzip would be something like this:

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