I had to implement this myself recently and found that existing answers had a few errors, so here's my take with how it works today.
import java.util.Collections;import java.util.zip.Inflater;import okhttp3.Headers;import okhttp3.Interceptor;import okhttp3.MediaType;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.RequestBody;import okhttp3.Response;import okhttp3.ResponseBody;import okio.BufferedSource;import okio.GzipSource;import okio.InflaterSource;import okio.Okio;var client = new OkHttpClient.Builder() .addInterceptor( (Interceptor.Chain chain) -> { var oldRequest = chain.request(); // If the caller has passed their own Accept-Encoding // it's indicating they expect to handle it themself. if (oldRequest.header("Accept-Encoding") != null) { return chain.proceed(oldRequest); } // Augment request saying we accept multiple content encodings var newHeaders = oldRequest .headers() .newBuilder() .add("Accept-Encoding", "deflate") .add("Accept-Encoding", "gzip") .build(); var newRequest = oldRequest.newBuilder().headers(newHeaders).build(); var oldResponse = chain.proceed(newRequest); // Replace the response's request with the original one var responseBuilder = oldResponse.newBuilder().request(oldRequest); // We might not have a body to decompress var body = oldResponse.body(); if (body != null) { BufferedSource source = body.source(); // The body may have been wrapped in an arbitrary encoding sequence // and the server returns them in the order it encoded them // so we wrap them with decoders in reverse order. var encodings = oldResponse.headers().values("Content-Encoding"); Collections.reverse(encodings); for (var encoding : encodings) { if ("deflate".equalsIgnoreCase(encoding)) { var inflater = new Inflater(true); source = Okio.buffer(new InflaterSource(source, inflater)); } else if ("gzip".equalsIgnoreCase(encoding)) { source = Okio.buffer(new GzipSource(source)); } } // Strip encoding and length headers as we've already handled them var strippedHeaders = oldResponse .headers() .newBuilder() .removeAll("Content-Encoding") .removeAll("Content-Length") .build(); responseBuilder.headers(strippedHeaders); var contentType = MediaType.parse(oldResponse.header("Content-Type")); // Construct a new body with an inferred Content-Length var newBody = ResponseBody.create(contentType, -1L, source); responseBuilder.body(newBody); } return responseBuilder.build(); }) .build();