一、OKHTTP简介
OKHttp是一个处理网络请求的开源项目OKHttp GitHub地址
OKHttp优点
- 支持HTTP2/SPDY(SPDY是Google开发的基于TCP的传输层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。)
- socket自动选择最好路线,并支持自动重连,拥有自动维护的socket连接池,减少握手次数,减少了请求延迟,共享Socket,减少对服务器的请求次数。
- 基于Headers的缓存策略减少重复的网络请求。
- 拥有Interceptors轻松处理请求与响应(自动处理GZip压缩)。
OKHttp的功能
- PUT,DELETE,POST,GET等请求
- 文件的上传下载
- 加载图片(内部会图片大小自动压缩)
- 支持请求回调,直接返回对象、对象集合
- 支持session的保持
二、OkHttp使用
此处只举例异步调用:
//1.创建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//2.创建Request对象,设置一个url地址(百度地址),设置请求方式。
Request request = new Request.Builder().url("http://www.baidu.com").method("GET",null).build();
//3.创建一个call对象,参数就是Request请求对象
Call call = okHttpClient.newCall(request);
//4.请求加入调度,重写回调方法
call.enqueue(new Callback() {
//请求失败执行的方法
@Override
public void onFailure(Call call, IOException e) {
}
//请求成功执行的方法
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
上面就是发送一个异步GET请求的4个步骤:
- 创建OkHttpClient对象
- 通过Builder模式创建Request对象,参数必须有个url参数,可以通过Request.Builder设置更多的参数比如:header、method等
- 通过request的对象去构造得到一个Call对象,Call对象有execute()和cancel()等方法。
- 以异步的方式去执行请求,调用的是call.enqueue,将call加入调度队列,任务执行完成会在Callback中得到结果。
注意事项:
- 异步调用的回调函数是在子线程,我们不能在子线程更新UI,需要借助于 runOnUiThread() 方法或者 Handler 来处理。
- onResponse回调有一个参数是response,如果我们想获得返回的是字符串,可以通过response.body().string()获取;如果希望获得返回的二进制字节数组,则调用response.body().bytes();如果你想拿到返回的inputStream,则调response.body().byteStream(),有inputStream我们就可以通过IO的方式写文件
三、OkHttpClient源码分析
1、先看内部类和构造函数的实现
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
//协议,支持http2和http1
static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(
Protocol.HTTP_2, Protocol.HTTP_1_1);
//连接规范,带有扩展的现代TLS连接 和 未加密、未经身份验证的连接
//具体作用先不看
static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);
static {
Internal.instance = new Internal() {
//加入请求头
@Override public void addLenient(Headers.Builder builder, String line) {
builder.addLenient(line);
}
//加入请求头
@Override public void addLenient(Headers.Builder builder, String name, String value) {
builder.addLenient(name, value);
}
//设置缓存
@Override public void setCache(OkHttpClient.Builder builder, InternalCache internalCache) {
builder.setInternalCache(internalCache);
}
//连接置空闲,两个参数ConnectionPool(连接池),RealConnection(真实连接)
//在连接池把真实连接置为空闲状态
@Override public boolean connectionBecameIdle(
ConnectionPool pool, RealConnection connection) {
return pool.connectionBecameIdle(connection);
}
//获取真实连接,通过address(地址)、StreamAllocation(流分配)、Route (线路)
//在连接池获取当前真实连接
@Override public RealConnection get(ConnectionPool pool, Address address,
StreamAllocation streamAllocation, Route route) {
return pool.get(address, streamAllocation, route);
}
//判断两个主机是否相同
@Override public boolean equalsNonHost(Address a, Address b) {
return a.equalsNonHost(b);
}
//消除重复连接
@Override public Socket deduplicate(
ConnectionPool pool, Address address, StreamAllocation streamAllocation) {
return pool.deduplicate(address, streamAllocation);
}
//加入连接池
@Override public void put(ConnectionPool pool, RealConnection connection) {
pool.put(connection);
}
//线路集合
@Override public RouteDatabase routeDatabase(ConnectionPool connectionPool) {
return connectionPool.routeDatabase;
}
//响应状态码
@Override public int code(Response.Builder responseBuilder) {
return responseBuilder.code;
}
//
@Override
public void apply(ConnectionSpec tlsConfiguration, SSLSocket sslSocket, boolean isFallback) {
tlsConfiguration.apply(sslSocket, isFallback);
}
//无效地址
@Override public boolean isInvalidHttpUrlHost(IllegalArgumentException e) {
return e.getMessage().startsWith(HttpUrl.Builder.INVALID_HOST);
}
//流分配
@Override public StreamAllocation streamAllocation(Call call) {
return ((RealCall) call).streamAllocation();
}
//异常
@Override public @Nullable IOException timeoutExit(Call call, @Nullable IOException e) {
return ((RealCall) call).timeoutExit(e);
}
//创建新的call
@Override public Call newWebSocketCall(OkHttpClient client, Request originalRequest) {
return RealCall.newRealCall(client, originalRequest, true);
}
};
}
final Dispatcher dispatcher;//任务调度,执行异步请求时的策略
final @Nullable Proxy proxy;//代理
final List<Protocol> protocols;//所支持的协议
final List<ConnectionSpec> connectionSpecs;//连接规范
final List<Interceptor> interceptors;//拦截器
final List<Interceptor> networkInterceptors;//网络拦截器
final EventListener.Factory eventListenerFactory;//负责监听整个连接请求的生命周期
final ProxySelector proxySelector;//代理选择器
final CookieJar cookieJar;//cookie缓存
final @Nullable Cache cache;//响应报文缓存
final @Nullable InternalCache internalCache;//OKhttp内部缓存
final SocketFactory socketFactory;//创建socket的工厂
final SSLSocketFactory sslSocketFactory;//ssl的socket工厂继承于SocketFactory
final CertificateChainCleaner certificateChainCleaner;//证书的获取和清除
final HostnameVerifier hostnameVerifier;//主机认证
final CertificatePinner certificatePinner;//该类用于约束哪些证书是可信的。 锁定证书可以防止对证书颁发机构相关的攻击。 它还阻止通过用户已知或未知的中间证书颁发机构建立的连接
final Authenticator proxyAuthenticator;//认证器
final Authenticator authenticator;//
final ConnectionPool connectionPool;//连接池
final Dns dns;//dns获取ip,OKHTTP尝试的顺序排列。如果与地址的连接失败,OKHTTP将重试与下一个地址的连接,直到要么建立连接,要么耗尽IP地址集,要么超过限制
final boolean followSslRedirects;//遵循SSL重定向
final boolean followRedirects;//遵循重定向
final boolean retryOnConnectionFailure;//重试连接失败
final int callTimeout;//请求超时
final int connectTimeout;//连接超时
final int readTimeout;//读超时
final int writeTimeout;//写超时
final int pingInterval;//ping 间隔时长
public OkHttpClient() {
this(new Builder());
}
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = Util.platformTrustManager();
this.sslSocketFactory = newSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
if (sslSocketFactory != null) {
Platform.get().configureSslSocketFactory(sslSocketFactory);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.callTimeout = builder.callTimeout;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}