项目中使用了 okhttp:2.7.5, 上层是Retrofit. 因为App端最经常出现的问题就是发现某页面不可用, 那么就需要可视化展示请求结果. 所以我参考了这个文章: https://github.com/square/okhttp/wiki/Interceptors , 并参考了代码

https://github.com/square/okhttp/blob/parent-2.7.5/okhttp-logging-interceptor/src/main/java/com/squareup/okhttp/logging/HttpLoggingInterceptor.java

进行了测试, 然而很惊讶的发现, request 中的Header总是为空, 具体代码:

@Override public Response intercept(Chain chain) throws IOException {

  Level level = this.level;

  Request request = chain.request();

// 此处省略若干行

    Headers headers = request.headers();

    for (int i = , count = headers.size(); i < count; i++) {

      String name = headers.name(i);

      // Skip headers from the request body as they are explicitly logged above.      if (!“Content-Type”.equalsIgnoreCase(name) && !“Content-Length”.equalsIgnoreCase(name)) {

        logger.log(name + ”: ” + headers.value(i));

      }

    }

那么总是为空, 问题出在哪里呢?后来发现 OkHttp支持两种类型的拦截器:

application 和 network interceptors.

区别如下, 但是并没有提到Http头的问题:

Application interceptors

  • Don’t need to worry about intermediate responses like redirects and retries.
  • Are always invoked once, even if the HTTP response is served from the cache.
  • Observe the application’s original intent. Unconcerned with OkHttp-injected headers like If-None-Match.
  • Permitted to short-circuit and not call Chain.proceed().
  • Permitted to retry and make multiple calls to Chain.proceed().

Network Interceptors

  • Able to operate on intermediate responses like redirects and retries.
  • Not invoked for cached responses that short-circuit the network.
  • Observe the data just as it will be transmitted over the network.
  • Access to the Connection that carries the request.

, 之前的代码是这样添加的应用拦截器:

okHttpClient.interceptors().add(logging)

, 现在修改为:

okHttpClient.networkInterceptors().add(logging);

问题解决.

但是一个新的问题又出现了:

如果网络出现故障比如域名解析失败的时候, 只会走 Application interceptors, 而完全不走 Network Interceptors, 这对异常处理来说是个灾难!

源码逻辑:

先走 应用拦截器, 没有异常时才会通过 Call 类的 

Response getResponse(Request request, boolean forWebSocket) throws IOException 方法

走入 HttpEngine, 这时候才会执行到NetworkInterceptors.

Header的真正加入是在这个方法里面开始进行的.

在HttpEngine中又加入了剩下的一些头包括Cookie等:

/** * Populates request with defaults and cookies. * * <p>This client doesn’t specify a default {@code Accept} header because it * doesn’t know what content types the application is interested in. */private Request networkRequest(Request request) throws IOException {

  Request.Builder result = request.newBuilder();

  if (request.header(“Host”) == null) {

    result.header(“Host”, Util.hostHeader(request.httpUrl()));

  }

  if (request.header(“Connection”) == null) {

    result.header(“Connection”“Keep-Alive”);

  }

  if (request.header(“Accept-Encoding”) == null) {

    transparentGzip true;

    result.header(“Accept-Encoding”“gzip”);

  }

  CookieHandler cookieHandler = client.getCookieHandler();

  if (cookieHandler != null) {

    // Capture the request headers added so far so that they can be offered to the CookieHandler.    // This is mostly to stay close to the RI; it is unlikely any of the headers above would    // affect cookie choice besides ”Host”.    Map<String, List> headers = OkHeaders.toMultimap(result.build().headers(), null);

    Map<String, List> cookies = cookieHandler.get(request.uri(), headers);

    // Add any new cookies to the request.    OkHeaders.addCookies(result, cookies);

  }

  if (request.header(“User-Agent”) == null) {

    result.header(“User-Agent”, Version.userAgent());

  }

  return result.build();

}

参考资料:

https://www.learn2crack.com/2016/06/retrofit-okhttp-logging-interceptor.html

compile ‘com.squareup.okhttp:logging-interceptor:2.7.5’

转载请注明:WebLogic Android 博客 » OkHttp 2.x 的 Interceptor 无法读取Http请求时发出的header的问题及解决方案