Okhttp请求流程源码解析
前言
最近发现以前学习过的好多东西,都忘记了,所以打算复习一次,并且通过输出博客来加深印象。Okhttp
准备分成两篇文章来讲解,这篇文章主要叙述一下Okhttp
的整体请求流程,第二篇文章则讲述一下Okhttp
中极为重要的拦截器。“深入交流”系列打算从一些第三方框架源码或者FrameWork
层源码入手,进行"深入"的交流,会持续输出下去,敬请期待。
1、Okhttp的同步请求和异步请求
在分析Okhttp
的源码之前,我们首先了解一下Okhttp
最基本的实现一次网络请求的方式。
Okhttp
的同步请求,如下:
//[1]、创建OkhttpClient对象
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(5000, TimeUnit.MILLISECONDS)
.build();
//[2]、请求报文创建,包含常用的请求信息,如url、get/post方法,设置请求头等
Request request = new Request.Builder()
.url("http://www.baidu.com")
.get()
.build();
//[3]、创建Call对象
Call call = client.newCall(request);
try {
//[4]、同步请求,发送请求后,就会进入阻塞状态,直到收到响应
Response response = call.execute();
Log.d(TAG, "requestNet: response");
} catch (IOException e) {
e.printStackTrace();
}
接下来看一下okhttp
的异步网络请求,如下:
// [1]、创建OkhttpClient对象
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(5000, TimeUnit.MILLISECONDS)
.build();
// [2]、请求报文创建,包含常用的请求信息,如url、get/post方法,设置请求头等
Request request = new Request.Builder()
.url("http://www.baidu.com")
.get()
.build();
// [3]、创建Call对象
Call call = client.newCall(request);
// [4]、发送异步请求,接收回调信息
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: request error......");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: request success......");
}
});
可以看到同步请求和异步请求的使用在前3
步都是相同的,只用在第4
步的时候同步请求调用的是call.execute()
方法,异步请求调用的是call.enqueue()
方法。接下来我们会根据异步请求来分析一下Okhttp
整体的请求流程,同步请求相对于异步请求来说,较为简单,掌握异步请求后再看同步请求,问题不大。。。
在正式分析源码之前我们先来看一下Okhttp
的请求流程图,从宏观的角度先对整体的请求流程有个印象,之后我们再从每一步流程的细节进行分析。我自己把整体的请求分成了8
个小步骤,在这8
步中,Dispatcher
较为重要,而Interceptors
作为整个网络请求的核心部分,那是相当重要。
2、异步请求流程分析
[1]、构建OkhttpClient对象
OkhttpClient:相当于配置中心,所有的请求都会共享这些配置,OkhttpClient
中定义了网络协议、DNS
、请求时间等等。创建对象的方式有两种,一种是通过直接new
对象的方式,另一种是通过Builder
模式设置参数来进行创建。
方法一:使用默认参数,不需要配置参数
OkHttpClient client = new OkHttpClient();
方法二:通过Builder来配置参数
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(5000, TimeUnit.MILLISECONDS)
.build();
两者的构造方法分别如下:
// 默认方式,这种方式不需要配置参数,使用的都是默认创建的参数
public OkHttpClient() {
this(new Builder());
}
// builder模式,通过Builder来配置参数
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
// 太多了,省略一部分
......
}
public Builder() {
//调度器,用于调度后台发起的网络请求,有后台总请求数和单主机总请求数的控制。
dispatcher = new Dispatcher();
//⽀持的应⽤层协议,即 HTTP/1.1、HTTP/2 等
protocols = DEFAULT_PROTOCOLS;
//应⽤层⽀持的 Socket 设置,即使⽤明⽂ 传输(⽤于 HTTP)还是某个版本的 TLS(⽤于 HTTPS)。
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
//管理 Cookie 的控制器。OkHttp 提供了 Cookie 存取的判断⽀持(即什么时候需要存 Cookie,什么时候需要读取Cookie,但没有给出具体的存取实现。
//如果需要存取 Cookie,你得⾃⼰写实现,例如⽤ Map 存在内存⾥,或者⽤别的⽅式存在本地存储或者数据库
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
//⽤于验证 HTTPS 握⼿过程中下载到的证书所 属者是否和⾃⼰要访问的主机名⼀致
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
//客户端和服务器之间的连接抽象为一个connection,
//每一个connection都会放到连接池当中,当请求的url是相同的时候可以进行复用
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
//在请求失败的时候是否⾃动重试。注意,⼤多数的请求失败并不属于 OkHttp 所定义的「需要重试」,
//这种重试只适⽤于「同⼀个域名的 多个 IP 切换重试」「Socket 失效重试」等情况
retryOnConnecti