在 使用OkHttp之前,我们可能用到更多的网络请求框架是 AsyncHttp , 或者直接使用Android 自带的 HttpUrlConnection 和 HttpClient 然后对其简单的封装,Okhttp开源之后,现在大部分项目均支持了 。
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
// 创建Request
Request request = new Request.Builder()
.url("http://www.baidu.com/")
.build();
// 同步获取到结果 (后面我们重点分析下 execute执行逻辑)
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
# RealCall.java
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
// 将本次请求添加到事件调度器中
client.dispatcher().executed(this);
// 今天的主角, 责任链获取到Response结果
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
上面Client执行调度器中的 excute方法,实际上就是将当前请求直接添加到这个同步的双端队列中,等待线程池中的队列被执行。
---------------getResponseWithInterceptorChain() 这个就是今天的主角拦截器,而拦截器就是使用了 责任链模式,我们看看OkHttp 是怎样通过责任链模式,一环接着一环 ,一个对象持有下一个对象的引用。
1: 构建5个拦截器放在 拦截器数组里面,然后作为参数新建一个RealInterceptorChain.java,作为第一个拦截器。(index= 0)
2: 通过当前 Chain.proceed(request) 获取当前的拦截器(就是你自定义的拦截器),并得到下一个 RealInterceptorChain (index + 1),传入 当前的拦截器
3:在当前的拦截器中因为 同步步骤2 保存了 下一个 Chain ,所以可以根据下一个 Chain.proceed() 来循环到下一个拦截器,同时你也可以在当前的拦截器中 对 Response追加自己的业务,然后返回Response
# RealCall.java
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
//责任链 实际上是像递归一样倒叙执行
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
//5、重试与重定向拦击器
interceptors.add(retryAndFollowUpInterceptor);
// 4、请求头等信息 拦截器
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//3、缓存配置 根据条件(存在响应缓存并被设置为不变的或者响应在有效期内)返回缓存响应设置请求头(If-None-Match、If-Modified-Since等) 服务器可能返回304(未修改)
interceptors.add(new CacheInterceptor(client.internalCache()));
//2、连接 拦截器
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
//1、流操作(写出请求体、获得响应数据)进行http请求报文的封装与请求报文的解析
interceptors.add(new CallServerInterceptor(forWebSocket));
// 新建一个 RealInterceptirChain.class 类,执行 责任链中抽象处理类的处理方法 proceed
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null,
0, originalRequest);
return chain.proceed(originalRequest);
}
# RealInterceptorChain.proceed
//拦截器列表,装载了所有拦截器
private final List<Interceptor> interceptors;
//拦截器列表索引 (从零开始,每次 新建一个RealInterceptorChain对象,index在新建时候就增加1)
private final int index;
//封装请求信息的对象
private final Request request;
//proceed方法执行次数
private int calls;
// 构造函数
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation
streamAllocation,
HttpCodec httpCodec, RealConnection connection, int index, Request request) {
this.interceptors = interceptors;
this.connection = connection;
this.streamAllocation = streamAllocation;
this.httpCodec = httpCodec;
this.index = index;
this.request = request;
}
========================================================================================
@Override
public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
/**
* 依次取出拦截器链表中的每个拦截器去获取Response
*/
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//如果索引值大于等于拦截器列表大小,就抛出异常,因为后续会出现数组越界的异常
if (index >= interceptors.size()) throw new AssertionError();
// 创建新的拦截器链对象,并将index索引+1
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
//获取当前拦截器
Interceptor interceptor = interceptors.get(index);
//执行拦截器的intercept方法获取结果,并将新的拦截器链对象传入(这就是当前对象保留下一个对象的引
用)
Response response = interceptor.intercept(next);
return response;
}
好重点来了,当我们自己需要给某个 拦截器 在Response追加一些返回内容时,那么我们可以自定义 Interceptor 重写 intercept函数即可
public class LogInterceptor implements Interceptor {
private static final String TAG = "LogInterceptor";
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Log.d(TAG, "request = " + request.toString());
Response response = chain.proceed(request);
long t2 = System.nanoTime();
//1e6d = 10的6的方
Log.d(TAG, "time cost = " + (t2 - t1) / 1e6d + "ms \n response = " + response.toString());
// chain.proceed(request) 将业务交给下一个责任认处理
return response;
}
}