浅析 OkHttp 的拦截器机制

来源:互联网 发布:ai汉化包for mac 编辑:程序博客网 时间:2024/06/05 11:51

1 概述

AOP 编程。每次的 proceed 是执行点,可以在执行点的前面和后面添加需要的业务逻辑。比如打打日志,失败重试,添加缓存等等

拦截器就是基于责任链模式,每个节点有自己的职责,同时可以选择是否把任务传递给下一个环节

拦截器的设计,可以像工厂流水线一样,传递用户发起的请求 Request,每一个拦截器完成相应的功能,从失败重试和重定向实现、请求头的修改和Cookie 的处理,缓存的处理,建立 TCP 和 SSH 连接,发送 Request 和读取 Response,每一个环节由专门的 Interceptor 负责

2 类和接口

2.1 Inteceptor

主要方法 Intercept。会传递一个 Chain 对象过来,可以在 Chain 在执行 proceed 的前后添加代码

2.2 Chain

主要方法 proceed。OkHttp 的唯一实现类是 RealInterceptorChain。内部维护了所有要执行的拦截器列表,在 proceed 内部会唤醒下一个 Interceptor ,调用 intercept 来进行下一步

public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,    Connection connection) throws IOException {  ...  RealInterceptorChain next = new RealInterceptorChain(      interceptors, streamAllocation, httpStream, connection, index + 1, request);  Interceptor interceptor = interceptors.get(index);  Response response = interceptor.intercept(next);  ...  return response;}

该类的主要成员有

  • List

    所有拦截器列表

  • StreamAllocation

    用来协调 Connection,Stream 和 Calls 的关系。封装了网络连接创建的一些策略。比如使用 RouteSelector 和 RouteDatabase 在建联失败后的多 IP 路由的选择;HttpStream 流的创建;Connection 的创建和使用 ConnectionPool 进行连接复用等

  • HttpStream

    网络数据流的抽象,因为不同的 HTTP 协议,流的传输方式不一样,有两个实现 Http1xStream 和 Http2xStream。主要的职责为写入 Request 请求,并且读取 Response 响应

  • Connection

    网络连接的抽象,唯一实现 RealConnection。主要用来管理连接用的 Socket。RealConnection 调用 connect 来进行Socket 连接

  • Request

    请求体的抽象,包括方法、请求头、请求体

RealInterceptorChain 对 proceed 进行了扩展,在拦截器链式传递的过程中增加了这些对象的传递。所以执行拦截器的时候,启动下一个拦截器的前,可以对这些对象进行创建或者修改,然后再传递给下一个拦截器,或者调用这些对象完成相应的功能。比如在 RetryAndFollowUpInterceptor 会创建 StreamAllocation,在 BridgeInterceptor 会修改 Request 的请求头,在 ConnectInterceptor 会调用 StreamAllocation 的 newStream 方法建立连接等等。

3 基本流程

Call 抽象了一次请求,唯一实现类为 RealCall

当我们调用 call.execute 发起请求后,整个请求的流程发生在下面的方法中

  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);  }

通过一系列拦截器进行链式操作,一环接一环,每个拦截器负责单独的任务,环环相扣完成整个请求

  • RetryAndFollowUpInterceptor

    用来实现连接失败的重试和重定向

  • BridgeInterceptor

    用来修改请求和响应的 header 信息

  • CacheInterceptor

    用来实现响应缓存。比如获取到的 Response 带有 Date,Expires,Last-Modified,Etag 等 header,表示该 Response 可以缓存一定的时间,下次请求就可以不需要发往服务端,直接拿缓存的

  • ConnectInterceptor

    用来打开到服务端的连接。其实是调用了 StreamAllocation 的newStream 方法来打开连接的。建联的 TCP 握手,TLS 握手都发生该阶段。过了这个阶段,和服务端的 socket 连接打通

  • CallServerInterceptor

    用来发起请求并且得到响应。上一个阶段已经握手成功,HttpStream 流已经打开,所以这个阶段把 Request 的请求信息传入流中,并且从流中读取数据封装成 Response 返回

请求的流程