okhttp源码解读--上篇(okhttpclient参数,enqueue/execute调用)

前两天刚刚把Retrofit的源码看完,发现对于底层的请求调用还是通过okhttp来进行的.
现在来研究一下okhttp的源码.
由于okhttp比retrofit细节,结构上要更复杂.预期以3个篇幅来进行讲解.
分别是:
上篇:okhttpclient的参数,调用.
中篇:getResponseWithInterceptorChain
下篇:各个Interceptor的作用和自定义Interceptor

okhttp

画个重点.
我们看完Retrofit后知道它的核心代码是 Proxy.newProxyInstance()
那么OkHttp的重点是什么呢?
getResponseWithInterceptorChain()

本次源码解读将基于OkHttp最新版本3.13.1进行.
我将以看过okhttp源码后的视角来写这篇流水账博客.


1.okhttp的用法.
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
          .url("https://api.github.com/")
          .build();

okHttpClient.newCall(request).enqueue(new Callback() {
         @Override
         public void onFailure(Call call, IOException e) {
                System.out.println("请求失败");
         }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
                System.out.println("请求成功");
         }
});

最常见的用法,我们先创建了一个OkHttpClient,然后通过Builder模式创建了一个Request,再将Request传到newCall()内,调用enqueue()/execute()即可.

这段基础调用代码,我们主要学习一下3个内容.

  1. OkHttpClient
  2. newCall
  3. enqueue/execute

2. OkHttpClient

这个主要的类,我们看一下全局的变量,几十个呢.
挑几个重点看一下吧.
反正看得懂就看,看不懂就关掉,千万别一棵树吊死了.(完全看不懂的,我就不写出来了,23333)

  • Dispatcher dispatcher
    这玩意主要功能就字面意思…是一个调度器.
    Flux的diapatcher负责全局调度传递Action.那我们看看okhttp的.
    在这里插入图片描述
    最大请求数量64、同一个Host最大请求数量5、idleCallback(闲置的callback)、executorService(线程池)、3个queue(分别是准备好的异步queue,正在运行的异步queue,正在运行的同步queue).
    okhttp内,dispather的作用是调度传递各种call,如RealCall/AsynCall.

    具体的作用等待看一下后续的,再思考具体的作用.

  • List protocols
    点进去看一下这个Protocol,
    emmm…
    HTTP_1_0、HTTP_1_1、SPDY_3、HTTP2、H2_PRIOR_KNOWLEDGE、QUIC
    下面还有一个get方法,传入对应的String protocol,给你匹配对应的Hypertext Transfer Protocol (超文本协议).
    我知道的也就http1.0、http1.1、spdy、http2.0了,其他的是什么鬼.
    反正知道了大概这就是okhttp支持的协议了.(我们常用的也就是http1.1罢了)

  • List connectionSpecs
    点进去看一下ConnectionSpec,
    CipherSuite !!!
    TLS打头的…
    这妥妥的就是HTTPS连接建立,TLS安全层 客户端和服务端Client Hello/Service Hello 使用的非对称加密/对称加密/HASH算法的 支持合辑了.

  • List interceptors/List networkInterceptors
    这2个Interceptor涉及到okhttp的最核心的东西getResponseWithInterceptorChain,后面再分析.

  • CookieJar cookieJar
    CookieJar这个东西,我还是认为有必要提一句的.
    在这里插入图片描述
    核心的就这2个方法了,
    当初最开始使用这个的时候,我也纠结过这是啥玩意.
    其实是很简单
    完全可以自己实现一下CookieJar,然后自己弄一个Map存储一下.

CookieJar I_NEED_COOKIES = new CookieJar() {

            Map<String, List<Cookie>> mCookie = new HashMap();

            @Override
            public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                mCookie.put(url.toString(), cookies);
            }

            @Override
            public List<Cookie> loadForRequest(HttpUrl url) {
                return mCookie.get(url.toString());
            }
        };

和Retrofit的ServiceMethodCache,loader.ProxyCache一样,有就直接拿,没有就存进去.

  • CertificatePinner certificatePinner
    这个东西也提一嘴.当在OkHttpClient创建时,可以通过额外添加一个CertificatePinner,使其在访问指定host时,直接校验本地写死的证书公钥,不进行多层证书和签名验证
OkHttpClient newOkHttpClient = new OkHttpClient.Builder()
                .certificatePinner(
                        new CertificatePinner.Builder().add("指定的host","证书公钥(sha256/XXXX)").build())
                .build();

对了,如果不记得证书公钥,可以直接随便写一个,log有返回正确的哟…

  • Other
    剩下的一些内容,要么就是很直观,看一样名字就能够了解的,要么就是我不会的,我就不班门弄斧了.

3. newCall

点进去看看,复读机
emmm…

RealCall.newRealCall(this, request, false /* for web socket */);

一个参数变3个参数,一个okhttpclient,一个传入的request,一个websocket.

临时插播一下webSocket的信息.
据我所知,webSocket的使用场景是那种需要 长连接,服务器频繁刷新数据的场景.比如说 金融?
听朋友说,智能家居方面也用这玩意了,最近面试问的还挺多?
完全没用过啊,开坑学习,研究预定!!!

再看看newRealCall().其实就是创建了一个RealCall.

RealCall call = new RealCall(client, originalRequest, forWebSocket);

OK,期待一下enqueue/execute在这个RealCall里面的调用吧.


4.enqueue/execute

终于到了关键的请求部分了.
让我们点进去看看 复读机.png

  • execute
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();

关键的代码就2行…
调用dispatcher的executed()方法,将这个包装着request的RealCall放到了runningSyncCalls这个queue里面去了.
然后就直接通过getResponseWithInterceptorChain()获取到了response…
这就结束了, 就是辣么简单.
有的人可能就要说了.不对啊,不是说okhttp请求是自己实现的socket连接么,
哪里连接了socket?又在哪里接受到了数据呢?咋就直接返回了?

  • enqueue
client.dispatcher().enqueue(new AsyncCall(responseCallback));

先看看这个dispatcher.enqueue做了什么.
1.先将这个包装着request的RealCall放到了readyAsyncCalls这个euque里面去了.
2.调用promoteAndExecute();
3.检查当前请求数量和同一Host下请求数量,将readyAsyncCalls的call放到runningAsyncCalls内.
4.使用一个叫做AsyncCall调用executeOn()
在这里插入图片描述

再看看enqueue传入的参数,刚好也是一个AsyncCall,巧了.
在这里插入图片描述
在这个AsyncCall内调用executeOn,也就是启用线程池来调用这个AsyncCall.
在这里插入图片描述
AsyncCall继承了NamedRunnable.看一眼这个runnbale的run(),然来调用的是execute();
execute()也通过getResponseWithInterceptorChain()拿到了response.

最后将response,通过在MainActivity里面创建的CallBack回调至Activity内.


总结.

okhttp的整体调用(enqueue/execute)逻辑,基本就是这样了.
发现最核心的HTTP请求处理部分都在getResponseWithInterceptorChain()里面了.

下一篇将开始讲解这个核心.

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用Okhttp进行文件上传时,需要注意设置请求头的Content-Type为multipart/form-data。这是因为在文件上传时,需要将文件数据以多部分的形式进行传输。\[1\]你可以使用Okhttp3库来实现这个功能。首先,你需要引入Okhttp3的jar包,可以通过在pom.xml文件中添加以下依赖来引入Okhttp3库: ```xml <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.0.0</version> </dependency> ``` 接下来,你可以使用Okhttp3的RequestBody类来创建一个请求体,然后将文件数据添加到请求体中。在创建RequestBody时,你需要指定Content-Type为multipart/form-data。这样后台才能正确解析请求并接收到数据。\[2\]如果你在设置请求头的Content-Type后仍然无法成功上传文件,可能是因为你没有正确设置RequestBody的Content-Type。你可以尝试在创建RequestBody时设置Content-Type为multipart/form-data,这样可以确保请求体的Content-Type与请求头中的Content-Type一致,从而解决上传文件的问题。\[3\] #### 引用[.reference_title] - *1* *3* [通过Okhttp3 post方式上传文件 Content-Type=multipart/form-data](https://blog.csdn.net/qq_15327175/article/details/130533804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [SpringBoot2.1.x,okhttp3网络请求之MultipartFile方式上传文件,multipart/form-data表单多文件+多参数](https://blog.csdn.net/p812438109/article/details/107943319)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值