1 概述
OkHttp 的拦截器就是基于责任链模式,每个节点有自己的职责,同时可以选择是否把任务传递给下一个环节
整个过程像工厂流水线一样,传递用户发起的请求 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 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 返回。