文档章节

OkHttp的Interceptor原理分析

林泳坛
 林泳坛
发布于 2016/03/03 13:48
字数 841
阅读 607
收藏 1

OkHttp的Interceptor原理分析

标签(空格分隔): Java OkHttp Interceptor Chain


样例

OkHttpClient mClient = new OkHttpClient();
CookieManager cookieManager = new CookieManager(new PersistentCookieStore(BaseApplication.instance()), CookiePolicy.ACCEPT_ALL);
mClient.setCookieHandler(cookieManager);
mClient.interceptors().add(chain -> {
    Request originReq = chain.request();
    HttpUrl httpUrl = originReq.httpUrl().newBuilder().addQueryParameter("auth_token", BaseApplication.instance().getToken()).build();
    Request.Builder reqBuilder = originReq.newBuilder();
    reqBuilder.header("mobile_platform", "android").url(httpUrl);
    Request req = reqBuilder.build();
    Response resp = chain.proceed(req);
    if (Settings.isDebug) {
    }
    return resp;
});
if (Settings.isDebug) {
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    mClient.interceptors().add(logging);
}

上面代码中,我已经向mClient中添加了两个拦截器。第一个用于给原来的请求添加一个auth_token查询参数,第二个用于在请求前后把请求的内容和响应的内容打出来到控制台中。

入口

首先,得把OkHttp的源码git下来,然后找到OkHttpClient类,再找到其中的newCall(request)方法。好,故事从这里开始。代码如下,

  /**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  public Call newCall(Request request) {
    return new Call(this, request);
  }

很简单,就是直接新建一个Call对象而已,所以关键不是这里,而是Call类。我们拿到Call对象之后一般是调用enqueue方法或者execute方法。我们就拿比较简单的execute方法来做切入点。对应的代码如下,

  public Response execute() throws IOException {
  
    ··· 这里省略了若干行代码
    
    try {
      client.getDispatcher().executed(this);
      Response result = getResponseWithInterceptorChain(false);
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.getDispatcher().finished(this);
    }
  }

上面代码中,关键在于getResponseWithInterceptorChain方法。最后我们的结果也就是从这个方法中产生的,代码如下,

  private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    return chain.proceed(originalRequest);
  }

  class ApplicationInterceptorChain implements Interceptor.Chain {
    private final int index;
    private final Request request;
    private final boolean forWebSocket;

    ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {
      this.index = index;
      this.request = request;
      this.forWebSocket = forWebSocket;
    }

    ··· 这里省略了若干行代码

    @Override public Response proceed(Request request) throws IOException {
      // If there's another interceptor in the chain, call that.
      if (index < client.interceptors().size()) {
        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
        Interceptor interceptor = client.interceptors().get(index);
        Response interceptedResponse = interceptor.intercept(chain);

        ··· 这里省略了若干行代码

        return interceptedResponse;
      }

      // No more interceptors. Do HTTP.
      return getResponse(request, forWebSocket);
    }
  }

从上面代码中,我们看到有一个ApplicationInterceptorChain这个种东西参与其中。这个东西是责任链设计模式的关键——链,它把多个处理器(对应这里的Interceptor)串联在一起,并且请求会在条链上传递下去,直到找到真正有责任处理这个请求的处理器(即这里的Interceptor)。上面代码中,我们可以看出,处理请求的责任落在了最后一个处理器上。

代码是最好的文档,我们看它的类定义。它实现了Chain接口,就是我们向OkHttpClient中添加Interceptor时接收到的参数。它的作用是记录当前Intercepter的索引(index)和Request对象,并且请求index对应的拦截器获取结果,并且把下链条的下一截作为参数传给拦截器。拦截器收到chain参数后,最终还是要调用chain的proceed方法。所以,这里就是一个递归过程,一直到最后一个拦截器,才真正的进入到OkHttp的网络请求核心获取数据。获取到数据之后,Response就会在拦截器中逆向传递。

声名

By 啪嗒科技 AtanL(atanl@padakeji.com)

©啪嗒科技版本所有,没有经作者允许,只能发表于padakeji.com相关域名下。

© 著作权归作者所有

共有 人打赏支持
林泳坛
粉丝 3
博文 18
码字总数 13321
作品 0
广州
程序员
Android面试的那些答不上来的问题(一)--- OkHttp的拦截器你到底了解多少(上)

前言 前段时间面试了很多家公司(坐标成都,大大小小加起来得20家吧),有时候有些事做多了,你就会发现它的一些窍门或者规律,面试这件事当然也不例外。其实很多公司问到的问题都大同小异,...

SillyMonkey
05/10
0
0
Android面试有迹可循(一)OkHttp3.9拦截器原理与区别

接上回 传送门 上回我们讲到,OkHttp的请求过程中有个非常重要的东西-“拦截器”,而且拦截器又分为interceptors和networkInterceptors两种,那它们具体有何区别呢?又要怎么来使用?现在来一...

SillyMonkey
05/19
0
0
OkHttp 3.11.0 发布,轻量的 Java 网络请求框架

OkHttp 3.11.0 已发布,OkHttp 是一个轻量的 Java 网络请求框架。 本次更新内容如下: OkHttp's new okhttp-tls submodule tames HTTPS and TLS. OkHttp now supports prior knowledge clear......

淡漠悠然
07/15
0
0
feign和okhttp的结合

背景 使用feign可以很方便的调用各种http接口 http请求神器之Feign 那么feign是如何做到的呢? 分析 本质上默认场景feign仍然是使用httpClient进行调用的。 通过声明式的RequestMapping等注解...

Mr_Qi
07/11
0
0
Xutils, OKhttp, Volley, Retrofit对比

Xutils这个框架非常全面,可以进行网络请求,可以进行图片加载处理,可以数据储存,还可以对view进行注解,使用这个框架非常方便,但是缺点也是非常明显的,使用这个项目,会导致项目对这个框...

安卓笔记侠
08/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Go语言_通神之路(2)

1、包 每个Go程序都是由包构成,从main包开始运行,就是我上一篇讲到的,都是从main函数开始执行,但是必须在main包下面! package mainimport ( "fmt" "math/rand")func ...

木九天
昨天
2
0
51.php-fpm的pool 慢日志 open_basedir 进程管理

12.21 php-fpm的pool 12.22 php-fpm慢执行日志(测试时报错) 12.23 open_basedir 12.24 php-fpm进程管理 12.21 php-fpm的pool: php-fpm里的pool也叫池子,咱们之前加入过www的配置,这个w...

王鑫linux
昨天
0
0
java内存模型概述

1、Java虚拟机运行时数据分区图 程序计数器:线程私有,是一块较小的内存空间,它是当前线程所执行的字节码文件的行号指示器 java虚拟机栈:线程私有,其生命周期与线程相同,这也就是我们平...

京一
昨天
0
0
shell学习之test语法

因为if-then语句不能测试退出状态码之外的条件,所以提供了test, 如果test命令中列出的条件成立,test命令就会退出并返回退出状态码0;如果条件不成立,test命令就会退出并返回非零的退出状态...

woshixin
昨天
0
0
openJDK之如何下载各个版本的openJDK源码

如果我们需要阅读openJDK的源码,那么需要下载,那么该去哪下载呢? 现在JDK已经发展到版本10了,11已经处于计划中,如果需要特定版本的openJDK,它们的下载链接在哪呢? 1.openJDK的项目 链接...

汉斯-冯-拉特
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部