OkHttpClient
学习和使用
先通过一个非常简单的例子来看怎样使用OKHttpClient
发送一个请求,然后根据这个简单例子来详细的分析每个步骤。
OkHttpClient client = new OkHttpClient().newBuilder().build();
Request request = new Request.Builder().url("http://www.baidu.com").build();
Response response = client.newCall(request).execute();
ResponseBody responseBody = response.body();
这是一个通过OkHttpClient
发送一个简单的get
请求百度首页的过程。
- 创建一个
OkHttpClient
实例 - 创建一个
Request
实例 - 使用
OkHttpClient
创建一个Call
并执行execute()
方法,得到一个Response
对象。 - 对
Response
进行相关操作。
以上就是整个简单HTTP请求的发送和接收过程。
OkHttpClient
实现了Cloneable
和Call.Factory
接口,Cloneable
接口表示okhttpclient
支持Object的clone方法。Call.Factory
接口是通过Request
创建一个Call
。同时也要实现Call.Factory
的newCall
方法。
OkHttpClient
通过内部的Builder类来创建。生成器模式,new OkHttpClient(){ this(new Builder())}
或者new OkHttpClient.Builder().build()
.创建OkHttpClient
的方式比较多,这样都是使用默认的OkHttpClient
的配置。
相关可以配置的和Client相关的还有
private static final List DEFAULT_PROTOCOLS = Util.immutableList(
Protocol.HTTP_2, Protocol.SPDY_3, Protocol.HTTP_1_1);
//默认支持的协议
private static final List DEFAULT_CONNECTION_SPECS = Util.immutableList(
ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT);
//使用https的版本和密码套件
final Dispatcher dispatcher;//调度,异步请求
final Proxy proxy;//代理 java.net
final List protocols;
final List connectionSpecs;
final List interceptors;//拦截器
final List networkInterceptors;//网络拦截器
final ProxySelector proxySelector;//代理选择器
final CookieJar cookieJar;//http cookies 管理方案和 持久化
final Cache cache;//缓存
final InternalCache internalCache;//内部缓存
final SocketFactory socketFactory;//socket 工厂 java.net
final SSLSocketFactory sslSocketFactory; //SSLSocket 工厂 java.net.ssl
final CertificateChainCleaner certificateChainCleaner;//证书方案
final HostnameVerifier hostnameVerifier;//hostName 校验 OkHostnameVerifier
final CertificatePinner certificatePinner;//固定的证书
final Authenticator proxyAuthenticator;//代理的身份认证
final Authenticator authenticator;// web的身份认证
final ConnectionPool connectionPool;//连接池
final Dns dns;//DNS
final boolean followSslRedirects;//是否 执行 ssl redirect
final boolean followRedirects;//是否执行 redirect
final boolean retryOnConnectionFailure; //连接失败后是否重试
final int connectTimeout;//连接超时时间
final int readTimeout;// 读取超时
final int writeTimeout;// 写入超时
Request
和Client一样也是使用生成器模式完成的。
Request
中包含了
private final HttpUrl url;
private final String method;
private final Headers headers;
private final RequestBody body;
private final Object tag;
private volatile CacheControl cacheControl; // Lazily initialized.
Request
中包含的内容都是比较清晰的,一个是HttpUrl
对象。主要内容就是请求地址,实例化的时候可以指定,协议,端口等。method就是指请求方法,Headers
是请求头的封装。RequestBody
就是请求主体。
HttpUrl
的使用
HttpUrl url = new HttpUrl.Builder()
.scheme("https")
.host("www.baidu.com")
.addPathSegment("s")
.addQueryParameter("wd", "dota2")
.build();
System.out.println(url);
// https://www.baidu.com/s?wd=dota2
得到了一个HttpUrl
。还有很多其他的方法:
queryParameterName()
和queryParameterValue
获取get请求参数 等。
RequestBody
是一个抽象类。还有两个子类FormBody
和MultipartBody
。主要差别在于MediaType
.
回到例子中的Request
对象,使用了默认的Request.Builder()
来构建。默认的是get方法,默认的Header.Builder
。tag默认是自身。
OkHttpClient
实现了Call.Factory
接口,创建一个Call
。
public Call newCall(Request request) {
return new RealCall(this, request);
}
实际上接下来的工作都是由RealCall
在完成的。
根据client和request创建一个RealCall实例,client被final修饰。默认会加上RetryAndFollowUpInterceptor
参数。
protected RealCall(OkHttpClient client, Request originalRequest) {
this.client = client;
this.originalRequest = originalRequest;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
}
然后就是execute()
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
- 检查这个Call是否被执行过
- 利用
client.dispatcher.execute(this)
来完成实际的请求过程。Dispatcher
在client文档中的表示的是异步请求的调度。实际上同步请求也是通过他们来调度完成的 -
Reqsponse
是通过getResponseWithInterceptorChain()
方法获得的。从方法名可知,会通过一系列的拦截器。 - 最后通知
dispatcher
执行完成。
具体的Dispatcher
稍后看,先关注发送请求解析返回结果的getResponseWithInterceptorChain()
。
private Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
这个方法把网络请求,重试,缓存,压缩等操作都统一成一个个Interceptor。形成一个Interceptor.Chain
,最后完成一次请求的过程。
通过getResponseWithInterceptorChain()
可以看出Interceptor.Chain
的组成部分:
-
client.interceptors
构造client
的时候设置的Interceptors
-
retryAndFollowUpInterceptor
负责失败重试和重定向。this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
在构造RealCall
时创建。 - 桥接,将请求转换成发送到服务器的请求、通过网络响应构造一个服务器的返回响应d的
BridgeInterceptor
。 - 读取缓存返回,更新缓存的
CacheInterceptor
。 - 和服务器创建连接的
ConnectInterceptor
。 -
CallServerInterceptor
makes a network call to the server 最后一个Interceptor.
然后创建一个Interceptor.Chain
实例,执行proceed方法。得到Response
.