文档章节

OkHttp的Interceptor原理分析

林泳坛
 林泳坛
发布于 2016/03/03 13:48
字数 841
阅读 633
收藏 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
OkHttp优雅的实现下载监听

OkHttp优雅的实现下载监听 (ps:很久很久没有发什么博文了,打字都要锈了,请允许我在这里水一波~~) 我们都知道okhttp的运转原理,通过interceptor拦截器一层一层嵌套执行。要实现下载监听,...

北纬34点8度
08/21
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

没有更多内容

加载失败,请刷新页面

加载更多

Linux安装MySQL的两种方法

1. 运行平台:CentOS 6.3 x86_64,基本等同于RHEL 6.3 2. 安装方法: 安装MySQL主要有两种方法:一种是通过源码自行编译安装,这种适合高级用户定制MySQL的特性,这里不做说明;另一种是通过...

onedotdot
19分钟前
3
0
phpize源码安装php扩展

4、进入源码中的ext/pcntl目录 ~# cd php-5.3.29/ext/pcntl/ 5、运行 phpize 命令 ~# phpizeConfiguring for:PHP Api Version: 20090626Zend Module Api No: 20090626......

bengozhong
28分钟前
1
0
Git 常用技巧

# Git 常用技巧 ## 暖场 - Git 怎么读 ? - Git 的作者是谁 ? - 谁没有 Github 账号 ? - 谁没有在 Github 提交过 issues,PR ? - 谁没有不会用命令操作 Git ? ## Git 简介 Git 是一种代码...

帝子兮
40分钟前
1
0
MySQL学习笔记

踩坑建议 对于时间相关字段,为插入及显示毫秒数据,建议使用datetime(6)类型,并设置数据库客户端显示毫秒相关数据

OSC_fly
40分钟前
0
0
spring配置文件中xsd引用异常

异常: org.xml.sax.SAXParseException; lineNumber: 78; columnNumber: 69; schema_reference.4: 无法读取方案文档 'http://www.springframework.org/schema/tx/spring-tx-3.2.xsd', 原因为......

zaolonglei
43分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部