How to remove the request header parameters automatically added by user agent, accept encoding and other frameworks from OkHttp

Keywords: encoding network OkHttp

When using the OkHttp network framework to make network requests, we will find that there will be several additional parameters in the request header sent to the background than we added ourselves. Check the source code and you will find

 private Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!retryAndFollowUpInterceptor.isForWebSocket()) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(
        retryAndFollowUpInterceptor.isForWebSocket()));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

OkHttp will add a BridgeInterceptor by default, and check the source code of BridgeInterceptor

MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }
    }

    if (userRequest.header("Host") == null) {
      requestBuilder.header("Host", hostHeader(userRequest.url(), false));
    }

    if (userRequest.header("Connection") == null) {
      requestBuilder.header("Connection", "Keep-Alive");
    }

    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    // the transfer stream.
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }

    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }

    if (userRequest.header("User-Agent") == null) {
      requestBuilder.header("User-Agent", Version.userAgent());
    }

User agent, accept encoding and other request header parameters will be added by default in BridgeInterceptor. Sometimes we don't need these added parameters by default, so how can we remove them?

Through part of the source code in the first paragraph above

    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!retryAndFollowUpInterceptor.isForWebSocket()) {
      interceptors.addAll(client.networkInterceptors());
    }

We can see that the network interceptors are added only after the bridgeinterceptors are added in OkHttp, so we need to use the network interceptor to intercept the request headers again and operate the header parameters.

First, we need to customize an interceptor to remove parameters we don't need in the interceptor.

public class NetInterceptorimplements Interceptor {

    private HttpClient builder;

    public NetInterceptor() {
        super();
    }

    public NetInterceptor(HttpClient builder) {
        this.builder = builder;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        //Remove header parameters
        request = request.newBuilder()
                    .removeHeader("User-Agent")
                    .removeHeader("Accept-Encoding")
                    .build();
        Response response = chain.proceed(request);
        if (response.body() != null && response.body().contentType() != null) {
            MediaType mediaType = response.body().contentType();
            String content = response.body().string();
            ResponseBody responseBody = ResponseBody.create(mediaType, content);
            return response.newBuilder().body(responseBody).build();
        } else {
            return response;
        }
    }

}

Then set the custom interceptor as a network interceptor

  mOkBuilder = new Builder()
                .connectTimeout(mbuilder.getConnectTimeout(), TimeUnit.SECONDS)
                .readTimeout(mbuilder.getReadTimeout(), TimeUnit.SECONDS)
                .writeTimeout(mbuilder.getWriteTimeout(), TimeUnit.SECONDS)
                .sslSocketFactory(createSSLSocketFactory(), new TrustAllCerts())// Trust all certificates
                .hostnameVerifier(new TrustAllHostnameVerifier())
                .cookieJar(new CookieJar() {
                    private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();

                    @Override
                    public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list) {
                        cookieStore.put(httpUrl.host(), list);
                    }

                    @Override
                    public List<Cookie> loadForRequest(HttpUrl httpUrl) {
                        List<Cookie> cookies = cookieStore.get(httpUrl.host());
                        return cookies != null ? cookies : new ArrayList<Cookie>();
                    }
                });

  NetInterceptor netInterceptor = new NetInterceptor(mbuilder);
  //mOkBuilder.addNetworkInterceptor(netInterceptor); / / setting the application interceptor is invalid because the BridgeInterceptor was added after the interceptor was applied
  mOkBuilder.addNetworkInterceptor(netInterceptor);

In this way, the request header parameters automatically added by BridgeInterceptor can be removed.

Posted by runfastrick on Thu, 13 Feb 2020 11:42:52 -0800