OkHttp的功能
OkHttp是Android以及Jdk中封装了一套关于网络协议的库。主要实现了网络相关的功能:
- 支持Http1.0以及Http2.0
- 支持WebSocket
- 支持RESTFul的网络API
- 实现Post、Get、Delete等请求
- 内部处理重试以及重定向
- 允许增加请求缓存
OkHttp的使用
OkHttp的使用也非常简单。
- 通过
OkHttpClient.Builder
设置Dns
、Cache
、Proxy
等等 - 通过
Request.Builder
生成请求的相关数据 - 通过
OkHttpClient.newCall
生成一个Http的请求 - 通过
enqueue
或者excute
开始请求,在Callback中接收请求参数
// 配置OkHttpClient
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
clientBuilder.addInterceptor(...);
// 生成Post请求的请求参数
FormBody formBody = new FormBody.Builder()
.add("username", "admin")
.add("password", "admin")
.build();
// 生成Http请求实体
final Request request = new Request.Builder()
.url("http://www.jianshu.com/")
.post(formBody)
.build();
Call call = client.build().newCall(request);
// 加入请求队列中
call.enqueue(new Callback=>...);
OkHttp的设计思想
从下图可以看到OkHttp的设计核心思想 - Chain of Responsibility
:
- 应用发送
Request
,Request
会经过Application Interceptor
处理后,交付给OkHttp Core
-
OkHttp Core
接收请求后,会从Cache
中获取相应的Response
- 如果没有找到的话,则会将
Request
经过Network Interceptor
处理过后,发送给Server - 在接收到
Response
之后,也会经过Network Interceptor
以及Application Interceptor
处理后返回应用
OkHttp设计思想
OkHttp的源码分析
getResponseWithInterceptorChain
在RealCall
中,通过getResponseWithInterceptorChain
会完成以下事情:
- 对
Request
的Interceptor
的处理 - 创建Socket连接,发送Http请求报文
- 接收响应报文,处理请求失败的重试,以及302等重定向
- 处理缓存策略
而这一切,都在interceptors
以及RealInterceptorChain
中进行的处理。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> 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 (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
forWebSocket
字段标识当前OkHttpClient是否使用的WebSocket来进行的请求
RealInterceptorChain.proceed
在RealInterceptorChain.proceed
中,开始按照interceptors
的顺序开始责任链处理:
- 首先处理用户自定义的
interceptors
- 接着再处理
RetryAndFollowUpInterceptor
- 再处理
BridgeInterceptor
以及CacheInterceptor
- 再处理
ConnectInterceptor
与CallServerInterceptor
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
interceptors
按照顺序开始执行是很重要的,因为有一些变量会在之前的责任链interceptor中被初始化,所以顺序很重要
RetryAndFollowUpInterceptor.intercept
在该函数中,主要完成了:
- 创建
StreamAllocation
- 从
OkHttpClient
中保存Http的连接池connectionPool
,以便后续请求复用连接 - 构建Address对象,传入SSL、Dns等相关信息
- 在
followUpRequest
中根据Response Code来判断是否是需要重定向
- 从
@Override public Response intercept(Chain chain) throws IOException {
...
// 创建StreamAllocation为ConnectionInterceptor服务
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
while (true) {
...
try {
// 将请求交付后面的Interceptor进行处理,等待结果
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
}catch(Exception e){ ... }
} finally { ... }
...
Request followUp;
try {
// 处理重定向的结果
followUp = followUpRequest(response, streamAllocation.route());
} catch (IOException e) {
streamAllocation.release();
throw e;
}
...
}
在
realChain.proceed
之前,都是对Request
进行的处理,而在该函数之后,都是对Response
进行的处理。即,一个Interceptor
里面就包含了Request
以及Response
的处理。
ConnectInterceptor.intercept
中间还有BridgeInterceptor
以及CacheInterceptor
就不说了,它们只是对Cookie以及缓存的判断与处理。与真正的链接无关。
这个Interceptor中主要完成:
- 通过
streamAllocation.newStream
创建HttpCodec,可能是Http1Codec,也可能是Http2Codec分别对应Http1.0和Http2.0的请求
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
StreamAllocation.newStream
该函数主要会完成这几件事:
- 从
ConnectionPool
中根据Address
获取对应的Connection
- 调用
RealConnection.connect
开始连接- 调用
connectSocket
,创建Socket
- 调用
Socket.connect
开始连接
- 调用
- 调用
establishProtocol
开始建立链接- 如果不是Https的话,则判断是否是Http2.0,如果是,则调用
startHttp2
创建http2Connection
Http2.0的连接,并且将协议赋值为Protocol.H2_PRIOR_KNOWLEDGE
- 如果不是Http2.0话,直接使用
rawSocket
发送数据,并且将协议赋值为Protocol.HTTP_1_1
- 如果是Https的话,则会通过
connectTls
来建立SSL链接,包括SSL握手,证书验证等等
- 如果不是Https的话,则判断是否是Http2.0,如果是,则调用
- 最后调用
resultConnection.newCodec
,判断http2connection
是否为空,来生成Http1Codec还是Http2Codec
CallServerInterceptor.intercept
在之前建立完连接后,在这个Interceptor中,会开始发送数据,并且接收Response。
@Override public Response intercept(Chain chain) throws IOException {
HttpCodec httpCodec = realChain.httpStream();
Request request = realChain.request();
...
// 通过Codec写请求头
httpCodec.writeRequestHeaders(request);
Response.Builder responseBuilder = null;
// 接收Response头
responseBuilder = httpCodec.readResponseHeaders(true);
long contentLength = request.body().contentLength();
CountingSink requestBodyOut =
new CountingSink(httpCodec.createRequestBody(request, contentLength));
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
// 写Request的Body
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
// 写入请求结束符
httpCodec.finishRequest();
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
if (code == 100) {
// server sent a 100-continue even though we did not request one.
// try again to read the actual response
// 读取Response头部数据
responseBuilder = httpCodec.readResponseHeaders(false);
response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
...
if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
// 读取Response Body
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
...
return response;
}
网友评论