我爱编程

浅谈 okhttp

2018-05-28  本文已影响0人  柳岸风语

okhttpSquare公司开源的一个非常便捷的轻量级第三方网络访问框架。它支持同步请求和异步请求。使用起来也是非常的方便。用的人也是越来越多。作为有追求的码农,我们当然要知其怎么用,也要知道它是怎么实现的。那就闲话少说,马上发车。下面就是我自己总结的OkHttp流程图:

未命名文件.jpg
整个OkHttp的请求大致就是上面图片里面的过程,下面我将按照上面的流程图来一步一步解析okhttp的请求过程;

1、OkHttpClient的创建

OkHttpClient的创建我们一般都会选择使用OkHttpClient.Builder,这里我们可以设置一些我们发起请求的一些设置,比如我们自定义的拦截器,缓存啊,超时控制等,可以设置的参数,这里就不具体说了,我们在实际应用的时候自己按需要设置吧。

mOkHttpClient = new OkHttpClient.Builder()
                .callTimeout(10, TimeUnit.SECONDS)
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();

2、调用newCall(Request request)创建RealCall

RealCall是我们真正发起请求的类。它拥有两个比较重要的成员变量clientoriginalRequestclient当然好理解了,就是OkHttpClient的实例了,为什么持有他也很好理解了,既然是实际发起请求的类,客户端手动设置的请求设置当然也要起作用了。originalRequestRequest的实例,我们都知道Http请求包括请求头,请求链接,请求体等等,没错这个类就是包含这些东西的类。Request拥有ulrmethodheadersRequestBody这四个重要的成员变量,ulr代表请求链接,method代表请求方式(get,post等等),headers就是请求头了,RequestBody对应就是请求体了,像post请求就会设置请求体。下面代码表示的就是一个发起post的请求的Request了

private RequestBody createPostRequestBody(Map<String, Object> params) {
        FormBody.Builder bodyBuilder = new FormBody.Builder();
        if (params == null || params.isEmpty())
           return bodyBuilder.build();

        for (Map.Entry<String, Object> entry : params.entrySet()) {
            bodyBuilder.add(entry.getKey(), entry.getValue().toString());
        }

        return bodyBuilder.build();
 }

Request request = new Request.Builder()
                .post(createPostRequestBody(params))
                .url(url)
                .build();

3、发起请求

请求方式有两种,一种是同步请求,一种是异步请求。我们就先讲讲异步请求了。
RealCall的异步请求依赖Dispatcher类来执行。这个类是用来管理异步请求的,它有如下的成员:

    //异步请求最大并发请求数为64
    private int maxRequests = 64;
    //同一主机的异步请求最大并发请求数
    private int maxRequestsPerHost = 5;
    Runnable idleCallback;

    //请求执行的线程池
    private ExecutorService executorService;

    //将要执行的异步请求
    private final Deque<RealCall.AsyncCall> readyAsyncCalls = new ArrayDeque<>();

    //正在执行的异步请求
    private final Deque<RealCall.AsyncCall> runningAsyncCalls = new ArrayDeque<>();

    //正在执行的同步请求
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

它的执行逻辑大概是,先将异步请求放到readyAsyncCalls 等待执行,然后遍历readyAsyncCalls ,如果正在执行的请求数没有达到最大请求数,并且该请求请求的主机也没有到达最大请求书,就会发请求。
通过Dispatcher最终异步请求的执行会转移到AsyncCall的execute方法,接下来就是第四部了。同步请求就比较简单,各位看官们自己去看看源码吧!

4、执行getResponseWithInterceptorChain()

朋友们,终于来到了最核心的地方来了!这个方法里面使用责任链模式来执行拦截器,有点像View的事件传递。拦截器的执行顺序是先执行我们自定义的拦截器,然后是RetryAndFollowUpInterceptorBridgeInterceptorCacheInterceptorConnectInterceptornetworkInterceptorsCallServerInterceptor。这些拦截器是通过RealInterceptorChain一个一个连接起来,按顺序执行。RealInterceptorChain的最核心方法是proceed,这个方法的返回值是Response,这个东西我们就很熟悉嘞。proceed执行大致是:先创建一个新的RealInterceptorChain 对象next,这个next的拦截器下标加1,然后根据下标取出当前拦截器执行interdept方法,interdept方法又会执行next的proceed.。最终执行的轨迹是请求Request被一步步向下包装直到发起请求得到Response,然后Response被一步步向上处理,直到最顶层返回。接下来就是一步步分析拦截器的功能了。

// Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

5、RetryAndFollowUpInterceptor

这个Interceptor是处理失败重试和重定向处理。大致是经过下面几个检查

  1. 如果连接失败(未发起请求连接失败,请求已发送但连接中断),检查请求是否可以重试,如果可以就发起重试,否则任务请求失败;

  2. 请求成功,但需要判断请求是否需要重定向;判断是否重定向主要依据responseCode来判断以及发起请求的请求体是否支持多次请求。

6、BridgeInterceptor

顾名思义这是一个连接应用层代码和网络代码的桥梁,主要的功能是把我们写的请求代码翻译成http请求能识别的代码,然后把网络返回的Response翻译成我们可以识别的代码。

7、NetworkInterceptors

配置OkHttpClient时设置的 NetworkInterceptors。

8、CacheInterceptor

从名字上我们就知道这和缓存有关。

  1. 首先根据请求读取缓存
  2. 判断缓存是否可用
    1. 使用如果没有缓存,使用请求;
    2. 如果当前请求是https,但是缓存在请求的时候是否经过TLS 握手,如果没有,使用请求(这一块对网络请求不太了解,请大佬补充);
    3. 缓存是否应该被缓存,以及当前请求结果是否应该被缓存,如果不应该,使用网络请求;
    4. 如果请求设置了不使用缓存,或者请求了设置了If-Modified-Since或If-None-Match,使用网络请求;
    5. 检查http请求的缓存使用条件(这一块不是很懂,就不贻笑大方了);
    6. 如果经过上面的判断后,还是需要发起网络请求,并且当前请求设置不使用网络请求,这时候就认为请求失败了,cede是504;
  3. 网络请求成功,再判断是使用网络请求结果还是缓存请求结果,以及更新缓存;

8、ConnectInterceptor

这里主要是建立和服务器的连接通道。这里面涉及到通道的创建和复用,这里及不详细说了(其实我也不太懂,有时间再研究)。

9、CallServerInterceptor

向服务器发起请求。主要是向通道写入请求头,如果有请求体,也写入请求体,然后通过这个通道读取服务器返回的响应。

上一篇下一篇

猜你喜欢

热点阅读