浅谈 okhttp

作者: 柳岸风语 | 来源:发表于2018-05-28 16:55 被阅读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

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

    相关文章

      网友评论

        本文标题:浅谈 okhttp

        本文链接:https://www.haomeiwen.com/subject/eegylftx.html