您的位置:首页 > 理论基础 > 计算机网络

OKHttp源码解析(一) OkHttp整体流程

2018-02-05 11:52 609 查看
OkHttp官网地址:http://square.github.io/okhttp/

OkHttp GitHub地址:https://github.com/square/okhttp

本篇文章阐述一下OKHttp的整体流程。首先通过代码来一步一步进行分析它的内部流程。

源码环境

OKHttp3.2.0

1,基本用法

1.1,创建 OkHttpClient 对象

final OkHttpClient client = new OkHttpClient();


这是OKHttp提供的一个默认的构造函数,我们进去可以发现,它里面设置了一个默认的Builder,如果我们需要设置自己的Builder的话则可以使用它的有Builder参数的构造函数。

无参构造函数

public OkHttpClient() {
this(new Builder());
}


有参构造函数

private OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
//省略部分其他的参数...
}


构造完了对象后我们就可以发起请求了,请求分为同步请求和异步请求。我们首先来看下请求部分的代码。

1.2,发起http请求

//构造Request
Request request = new Request.Builder()
.url("https://github.com/crazyandcoder")
.build();

//响应结果
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
String  result= response.body().string());
}


网络请求方式一般有get、post、delete等等,这个请求中并没有设置是哪种请求方式,所以一般情况下都有设置的默认方法。

public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}


我们进去发现它的默认方式get。以上便是一个最简单,完整的请求流程。接下来我们分步进行分析一下。

2,请求类型

2.1,同步请求

OKHttp请求类型分为同步请求和异步请求,上面其实是用同步方式完成的网络请求。即:

Response response = client.newCall(request).execute();


我们进入发现execute它是接口Call中的方法,那么我们就去它的实现类中去查看它的实现方法。进入到client.newCall中查看。

@Override public Call newCall(Request request) {
return new RealCall(this, request);
}


其实真正实现call的是类RealCall,我们就去这个类中查看。

@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(false);
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}


因为这是一个同步请求方式,所在开始的时候就进行了判断,如果已经在执行的话就设置一下flag标明正在执行中,每个 call 只能被执行一次。

接着通过下面的代码来进行实际的请求,其中Dispatcher是Builder中的参数之一,即这是一个请求策略实现类。

client.dispatcher().executed(this);


执行完了请求之后通过getResponseWithInterceptorChain来返回相应结果

Response result = getResponseWithInterceptorChain(false);


接着通过dispatcher来通知结束请求。

我们来看下getResponseWithInterceptorChain方法里面的实现内容,通过名字可以简单看出这是一个关于拦截器的实现,拦截器,观察,修改以及可能短路的请求输出和响应请求的回来。通常情况下拦截器用来添加,移除或者转换请求或者回应的头部信息。

private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
return chain.proceed(originalRequest);
}


进入到方法中可以看出真正执行response的还是getResponse方法。由于getResponse方法太长我们一步一步分析。

Response getResponse(Request request, boolean forWebSocket)


首先判断进行RequestBody判断是否为null然后进行一系列的设置。

RequestBody body = request.body();
if (body != null) {
Request.Builder requestBuilder = request.newBuilder();

MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}

long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}

request = requestBuilder.build();
}


接着构造了一个HttpEngine,通过HttpEngine来发起请求以及读取响应结果,即:

//构造HttpEngine
engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);

//发送请求以及读取响应结果
engine.sendRequest();
engine.readResponse();


在读取响应结果中,又进行了是否有本地缓存cacheResponse进行判断,如果没有的话则进行网络请求networkResponse,否则就读取cacheResponse,最后将response返回。

Response response = engine.getResponse();
Request followUp = engine.followUpRequest();

if (followUp == null) {
if (!forWebSocket) {
engine.releaseStreamAllocation();
}
return response;
}


借用网上一张流程图来表示。



以上便是同步请求的一个整体流程,接着我们来分析下异步请求流程。

2.2,异步请求

client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}

@Override
public void onResponse(Call call, Response response) throws IOException {

}
});


OKHttp的异步请求其实是通过将请求Request插入到队列中,然后在回调中返回结果response的过程。下面我们来详细的了解一下异步请求。

从上面我们可以知道执行call的其实是RealCall,我们进入到里面看下enqueue的方法

@Override public void enqueue(Callback responseCallback) {
enqueue(responseCallback, false);
}

void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}


同样的一次只能执行一个call,接着我们看下AsyncCall类,其中存在excute方法。

@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
logger.log(Level.INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}


异步请求里面也是通过getResponseWithInterceptorChain来获取响应结果的,然后通过responseCallback的回调将onFailure和onResponse返回出去。

在发起请求时,整个框架主要通过Call来封装每一次的请求。同时Call持有OkHttpClient和HttpEngine。而每一次的同步或者异步请求都会有Dispatcher的参与。

3,总结

通过前两部分的学习分析,我们大概知道了一下OKHttp的使用流程。接下来我们通过一个流程图来总结一下OKHttp的使用流程。



后面的部分将针对每个环节进行详细的分析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: