举个栗子
1 | String url = "https://raw.github.com/square/okhttp/master/README.md"; |
源码分析
new OkHttpClient()
1 | public OkHttpClient() { |
new Request.Builder().url(url).build()
Builder()
1 | public Builder() { |
url()
1 | public Builder url(String url) { |
build()
1 | public Request build() { |
Request()
1 | Request(Builder builder) { |
发起HTTP请求
okHttpClient.newCall(request)
1 | @Override public Call newCall(Request request) { |
根据请求创建新的Call,主要起作用的是newRealCall()
同步请求execute()
1 | public Response execute() throws IOException { |
- 首先判断
call
是否执行过if (executed)
,每个call
只能执行一次,如果还想要一样的call,可以通过clone()
1 | @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state. |
client.dispatcher().executed(this);
执行call
,HTTP
请求的执行策略
getResponseWithInterceptorChain();
进行拦截操作,然后获得HTTP
的返回结果
getResponseWithInterceptorChain源码分析
1 | Response getResponseWithInterceptorChain() throws IOException { |
- 设置拦截器集合
List<Interceptor> interceptors = new ArrayList<>();
- 将配置
client
时候的拦截器加入集合interceptors.addAll(client.interceptors());
- 负责失败重试以及重定向
interceptors.add(retryAndFollowUpInterceptor);
- 负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应的
interceptors.add(new BridgeInterceptor(client.cookieJar()));
- 负责读取缓存直接返回、更新缓存
interceptors.add(new CacheInterceptor(client.internalCache()));
- 负责和服务器建立连接
interceptors.add(new ConnectInterceptor(client));
- 配置
OkHttpClient
时设置的interceptors.addAll(client.networkInterceptors());
- 负责向服务器发送请求数据、从服务器读取响应数据
interceptors.add(new CallServerInterceptor(forWebSocket));
client.dispatcher().finished(this);
通知dispatcher
执行完毕
异步请求enqueue()
1 | public void enqueue(Callback responseCallback) { |
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
…
}
```
dispatcher
在当前执行的时候如果还可以执行一个并发请求,那就立刻执行,否则加入runningAsyncCalls
队列,等待当前请求执行完成,然后再执行。
其他的和同步请求一样。
获取返回数据
在发起网络请求之后,我们就可以在Response
中获取到返回的数据,包括状态码、状态信息、返回头、responsebody
,返回的responsebody
可能会非常大,所以必须要用通过数据流的方式进行访问,其他部分可以随意获取。
responsebody
需要注意:
- 每个
body
只能被消费一次,多次消费会报异常 body
必须被关闭,不然会发生泄漏
HTTP缓存
之前的拦截器中,提到了负责缓存拦截器,所以在建立连接之前,我们应该检查相应是否被缓存、缓存是否可以用,如果是就直接返回缓存的数据,否则进行后面的步骤将返回的网络数据写进缓存。
缓存的具体缓存逻辑是在OkHttp中内置封装类一个Cache
类,利用DiskLruCache
,按照LRU
算法进行缓存淘汰。
总结
图源见水印