本文基于OKHttp3.2 。
一个典型 OKhttp 同步请求的发起是这样的:
|
|
在 OkHttpClient 类中, newCall 方法是这样的:
|
|
RealCall 是 Call 的实现类,那我们去 RealCall 中找,
|
|
很轻松就找到了 execute() 方法,上面代码第10行用到了一个从 OkHttpClient 获得的 Dispatcher 然后把它加入到分发器里面的队列 runningSyncCalls 中,在完成的时候会remove掉。这个队列是一个ArrayDeque。
|
|
|
|
其次会执行:
|
|
先到这儿,记住 getResponseWithInterceptorChain() 方法,我们再来看异步请求:
也在 RealCall 中:
|
|
是不是和同步很像,但是有两点不同:
1、同步调用的 executed 方法,而异步调用的是分发器的 enqueue 方法。
2、同步传入 execute 方法的参数是 Call,异步传入 enqueue 方法的是AsyncCall,这个是什么呢,这个是 Call 里面的一个内部类,而且是一个继承了Runnable的内部类。
先看第一个不同点:分发器的 enqueue 方法是干什么的?
|
|
|
|
很明显,这儿用线程池直接提交了这个实现了 Runable 的 AsyncCall 。
这是一个可缓存的线程池。
从上面代码我们看到异步请求是有条件限制的,默认最多64个请求,而对同一个主机的最大请求默认最多同时存在5个。这两个值都是可以更改的,Dispatcher 提供了相关方法。
|
|
|
|
|
|
OK,第一个不同点已经分析完,再来看看第二个不同点 AsyncCall 是个什么东东?
AsyncCall 继承自 NamedRunnable ,NamedRunnable 实现了 Runnable 。NamedRunnable 只是给这个 Runnable 起了个名字而已。
|
|
再来看看AsyncCall 的run里面的代码:
|
|
显然AsyncCall的execute才是核心。
|
|
在代码第八行我们又看到了getResponseWithInterceptorChain()方法。 可以看到,异步和同步一样,最后都执行到了这个方法并返回 Response 。
那我们就来看一下这个方法的实现:
|
|
创建了一个ApplicationInterceptorChain ,并且第一个参数传入0,这个0是有特殊用法的,涉及到OKHttp里面的一个功能叫做拦截器,从getResponseWithInterceptorChain这个名字里其实也能看出一二。先看看proceed做了什么:
OKHttp增加的拦截器机制,先来看看官方文档对Interceptors 的解释 :
Interceptors are a powerful mechanism that can monitor, rewrite, and
retry calls.
解释下就是拦截器可以用来转换,重试,重写请求的机制。
|
|
创建 ApplicationInterceptorChain 的时候第一个参数为0,则this.index==0;
若没有拦截器的话走 else,执行:
若有1个拦截器的话:
则0<1,回调拦截器中的 intercept 方法。
当我们在拦截器中手动调用 process 后再次回到方法中检查是否有拦截器,此时不满足条件,走 else,最终还是回到了 getResponse 方法。
看下我当时用的一个用于获取打印http请求信息的拦截器(包括请求头,body,url等等,直接打印):
|
|
这个拦截器发送完请求后打印的效果是这样的:
H快递: com.qht.blog2.Net.OK_LoggingInterceptor.intercept(OK_LoggingInterceptor.java:25)
H快递: 发送请求 http://www.kuaidi100.com/query?type=yunda&postid=7700008953907 on null
H快递: com.qht.blog2.Net.OK_LoggingInterceptor.intercept(OK_LoggingInterceptor.java:37)
H快递: 接收响应: [http://www.kuaidi100.com/query?type=yunda&postid=7700008953907]
返回json:【】 370.2ms
Server: nginx
Date: Tue, 13 Jun 2017 15:21:58 GMT
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
P3P: CP=”IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT”
Cache-Control: no-cache
Vary: Accept-Encoding
在处理完拦截器操作后,就进入到重要的getResponse方法,真正的去进行发送请求,处理请求,接收返回结果。
|
|
没错,就是这么长。
可以看到如果是post请求,先做一定的头部处理,然后新建一个HttpEngine去处理具体的操作,通过sendRequest发送具体请求操作,readResponse对服务器的答复做一定处理,最后得到从服务器返回的Response,讲到这里,我们整个的流程大概疏通了,代码贴了很多,简单的可以用下面一张图概括 :
getResponse() 方法的内容还有很多,下篇再分析。