1、概述
okhttp是一个第三方类库,用于android中请求网络。同时这是一个开源项目,用来替代HttpUrlConnection和HttpClient。
okhttp的源码地址在github上为:okhttp源码地址
okhttp的官网地址:okhttp官网地址
其一个简单的异步调用方法如下:
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
});
}
每一个HTTP请求中都包含一个URL,一个方法(如GET或POST),和一个请求头列表(headers)。请求还可以含有一个请求体(body):一个特定内容类型的数据流。
每一个HTTP响应中都包含一个状态码(如200代表成功,404代表未找到),一个响应头列表(headers)和一个可选的响应体(body)。
更多的okhttp用法可以参考其官方Wiki:okhttp Wiki
2、框架及源码分析
okhttp的整个流程如下图所示:
从这个流程图可以看出okhttp的整个请求与响应的流程就是Dispatcher不断从Request Queue里取出请求(Call),然后通过拦截器Interceptor一层层向下传递进行请求,获取到响应后再一层层通过拦截器Interceptor传回来。
其具体的函数调用链如下所示:
接下来我们具体分析一下各个相关的类及其核心函数。
2.1 OkHttpClient
OkHttpClient是整个okhttp的入口,创建它有两种方式:
OkHttpClient client =new OkHttpClient();
OkHttpClient client = new OkHttpClient.Builder()
.build();
其实第一种直接new的方式内部也是由一个建造出完成其初始化的
// OkHttpClient.class
public OkHttpClient() {
this(new Builder());
}
来看一下其真正构造方式:
// OkHttpClient.class
OkHttpClient(Builder builder) {
// 分发器Dispatcher对象,记录请求执行情况,内部维护一个线程池执行异步请求
this.dispatcher = builder.dispatcher;
// 代理设置,配置代理类型(直连,HTTP代理,Socket代理)以及Socket地址
this.proxy = builder.proxy;
// 协议集合,默认协议集合包括HTTP2,HTTP_1_1
this.protocols = builder.protocols;
// 连接规范,指定Socket连接的配置
this.connectionSpecs = builder.connectionSpecs;
// 应用拦截器集合
this.interceptors = Util.immutableList(builder.interceptors);
// 网络拦截器集合
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
// 事件监听器工厂
this.eventListenerFactory = builder.eventListenerFactory;
// 代理选择器
this.proxySelector = builder.proxySelector;
// Cookie瓶,为HTTP的cookies提供策略和持久化
this.cookieJar = builder.cookieJar;
// 磁盘缓存,内部使用DiskLruCache实现
this.cache = builder.cache;
// okhttp内部缓存,应用层不感知其存在
this.internalCache = builder.internalCache;
// socket工厂类
this.socketFactory = builder.socketFactory;
// HTTPs相关成员变量
...
// 连接池
this.connectionPool = builder.connectionPool;
// DNS
this.dns = builder.dns;
// 是否跟随SSL重定向
this.followSslRedirects = builder.followSslRedirects;
// 是否跟随重定向
this.followRedirects = builder.followRedirects;
// 连接失败是否重试
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
// 连接超时时间
this.connectTimeout = builder.connectTimeout;
// 读超时时间
this.readTimeout = builder.readTimeout;
// 写超时时间
this.writeTimeout = builder.writeTimeout;
// ping间隔时长
this.pingInterval = builder.pingInterval;
}
从其构造函数不难看出,该类可以让用户配置各种想配置的参数,从而实现个性化的请求。
OkHttpClient类里面有一个几乎一定会调用的方法:public Call newCall(Request request) 我们进入到里面看一下:
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
这一方法传入了一个Request的请求体,并最终输出一个RealCall。
2.2 Request
Request是用户设置的请求体,其在构建时也使用了建造者模式:
// Request.class
Request(Builder builder) {
// 请求url
this.url = builder.url;
// 请求方法
this.method = builder.method;
// 请求头
this.headers = builder.headers.build();
// 请求体
this.body = builder.body;
// 给该请求设置一个标志,用于可根据标志取消某一类请求
this.tag = builder.tag != null ? builder.tag : this;
}
同时可以对该请求配置单独的缓存策略:
// Request.class
public Builder cacheControl(CacheControl cacheControl) {
String value = cacheControl.toString();
if (value.isEmpty()) return removeHeader("Cache-Control");
return header("Cache-Control", value);
}
2.3 Call 和 RealCall
2.1节最后调用的newCall()方法里面构建了一个RealCall(),而该方法返回的是Call 。可以断定两者是一对抽象和具体实现。我们先看一下Call,它是一个接口类:
// Call.class
public interface Call extends Cloneable {
//返回当前请求
Request request();
//同步请求方法,此方法会阻塞当前线程知道请求结果放回
Response execute() throws IOException;
//异步请求方法,此方法会将请求添加到队列中,然后等待请求返回
void enqueue(Callback responseCallback);
//取消请求
void cancel();
//请求是否在执行,当execute()或者enqueue(Callback responseCallback)执行后该方法返回true
boolean isExecuted();
//请求是否被取消
boolean isCanceled();
//创建一个新的一模一样的请求
Call clone();
interface Factory {
Call newCall(Request request);
}
}
这个Call 里面定义了一些关于请求的方法,同时内部有一个接口子类,其内部有我们熟悉的newCall()方法。而这个子接口就是由OkHttpClient继承而实现的。接下来看一下Call 的具体实现类RealCall的构造方法:
// RealCall.class
final class RealCall implements Call {
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
//我们构建的OkHttpClient,用来传递参数
this.client = client;
this.originalRequest = originalRequest;
//是不是WebSocket请求,WebSocket是用来建立长连接的。
this.forWebSocket = forWebSocket;
//构建RetryAndFollowUpInterceptor拦截器
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
}
这里面除了将参数传入参数赋值给成员变量,同时初始化了我们在上面提到的第一个拦截器RetryAndFollowUpInterceptor。关于拦截器之后会详细说明。
当我们创建出Call 之后一般会调用其execute()方法或者enqueue(Callback responseCallback)方法来发起请求的调用。同时这两个方法也是真正请求开始的入口。
① 同步请求 execute()
// RealCall.class
@Override public Response execute() throws IOException {
// 判断该请求是否已经被执行过,即一个请求只能被执行一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
...
try {
// 交由Dispatcher处理请求
client.dispatcher().executed(this);
// 获取请求结果
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
② 异步请求
// RealCall.class
@Override public void enqueue(Callback responseCallback) {
// 判断该请求是否已经被执行过,即一个请求只能被执行一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
...
// 交由Dispatcher处理请求
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
从上面实现可以看出,不管是同步请求还是异步请求都是Dispatcher在处理:
同步请求:直接执行,并返回请求结果
异步请求:构造一个AsyncCall,并将自己加入处理队列中。
AsyncCall本质上是一个Runable,Dispatcher会调度ExecutorService来执行这些Runable。同时AsyncCall 是RealCall的内部类,所以它可以调用RealCall的成员变量。这边重点关注一下其执行函数execute(),该函数在其父类NamedRunnable 的run()中执行。
// RealCall.class
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
...
@Override protected void execute() {
boolean signalledCallback = false;
try {
// 获取请求结果
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
// 如果请求已经被取消,回调失败接口
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
// 不然就回调请求成功接口将请求结果回调出去
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// 只接受一次请求结果
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
// 获取请求是抛出异常,回调失败接口,并将异常回调回去
responseCallback.onFailure(RealCall.this, e);
}
} finally {
// 关闭dispatcher
client.dispatcher().finished(this);
}
}
}
从上面代码可以看出,不管是同步请求还是异步请求最后都会通过getResponseWithInterceptorChain()获取Response,只不过异步请求多了个线程调度,异步执行的过程。关于这个方法我们一会详细分析,先看一下Dispatcher这个类。
2.4 Dispatcher
// Dispatcher.class
public final class Dispatcher {
// 最大请求数
private int maxRequests = 64;
// 每个主机最大请求数
private int maxRequestsPerHost = 5;
...
// 线程池
private @Nullable ExecutorService executorService;
// 准备运行的异步请求
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
// 正在运行的异步请求
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
// 正在运行的同步请求
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
synchronized void executed(RealCall call) {
// 将同步请求加入正在运行的同步请求队列
runningSyncCalls.add(call);
}
synchronized void enqueue(AsyncCall call) {
//正在运行的异步请求不得超过64,同一个host下的异步请求不得超过5个
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
// 将异步请求加入正在运行的异步请求队列
runningAsyncCalls.add(call);
// 执行该异步请求
executorService().execute(call);
} else {
// 将异步请求加入准备运行的异步请求队列
readyAsyncCalls.add(call);
}
}
}
Dispatcher是一个任务调度器,它内部维护了三个双端队列:
readyAsyncCalls:准备运行的异步请求
runningAsyncCalls:正在运行的异步请求
runningSyncCalls:正在运行的同步请求
同步请求就直接把请求添加到正在运行的同步请求队列runningSyncCalls中,异步请求会做个判断:如果正在运行的异步请求不超过64,而且同一个host下的异步请求不得超过5个则将请求添加到正在运行的同步请求队列中runningAsyncCalls并开始执行请求,否则就添加到readyAsyncCalls继续等待。
2.5 Interceptor
讲完Dispatcher里的实现,继续来看getResponseWithInterceptorChain()的实现,这个方法才是真正发起请求并处理请求的地方。
//RealCall.class
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors. List interceptors = new ArrayList<>();
//自定义的Interceptor
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);
// 开始链式执行各个拦截器
return chain.proceed(originalRequest);
}
这几行代码,完成了对请求的所有处理过程,Interceptor将网络请求、缓存、透明压缩等功能统一了起来,它的实现采用责任链模式,各司其职,每个功能都是一个Interceptor,上一级处理完成以后传递给下一级,它们最后连接成了一个Interceptor.Chain。它们的功能如下:
RetryAndFollowUpInterceptor:负责重定向。
BridgeInterceptor:负责把用户构造的请求转换为发送给服务器的请求,把服务器返回的响应转换为对用户友好的响应。
CacheInterceptor:负责读取缓存以及更新缓存。
ConnectInterceptor:负责与服务器建立连接。
CallServerInterceptor:负责从服务器读取响应的数据。
位置决定功能,位置靠前的先执行,最后一个则负责与服务器通讯,请求从RetryAndFollowUpInterceptor开始层层传递到CallServerInterceptor,每一层都对请求做相应的处理,处理的结构再从CallServerInterceptor层层返回给RetryAndFollowUpInterceptor,最后请求的发起者获得了服务器返回的结果。以上便是Okhttp整个请求与响应的具体流程,可以发现拦截器才是Okhttp核心功能所在。
先看一下拦截器的接口类Interceptor:
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
// 返回请求将在其上执行。只网络连接拦截器实现该方法
@Nullable Connection connection();
}
}
这个接口类只有一个方法和一个Chain 内部接口类。而这个Chain 的实现类为上面getResponseWithInterceptorChain() 方法里面看到的RealInterceptorChain:
public final class RealInterceptorChain implements Interceptor.Chain {
// 拦截器集合
private final Listinterceptors;
// 流分配器
private final StreamAllocation streamAllocation;
// http编解码器
private final HttpCodec httpCodec;
// 连接对象
private final RealConnection connection;
// 目前调用的拦截器集合里面的拦截器位置
private final int index;
// 请求体
private final Request request;
// 该请求调用次数
private int calls;
public RealInterceptorChain(List interceptors, StreamAllocation streamAllocation,
HttpCodec httpCodec, RealConnection connection, int index, Request request) {
this.interceptors = interceptors;
this.connection = connection;
this.streamAllocation = streamAllocation;
this.httpCodec = httpCodec;
this.index = index;
this.request = request;
}
...
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// 如果我们已经有一个流,请确认传入的请求将使用它。
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// 如果我们已经有一个流,请确认这是对chain.proceed()的唯一调用。
// 也就是说每一个RealInterceptorChain ,proceed()只能调用一次
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// 调用链中的下一个拦截器。
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
// 获取响应体
Response response = interceptor.intercept(next);
// 确认下一个拦截器对chain.proceed()进行了必要的调用。
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// 确认拦截器的响应不为空。
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
return response;
}
}
有上面的代码可以看出,RealInterceptorChain 在调用proceed方法之后,会继续构建一个新的RealInterceptorChain对象,调用下一个interceptor来继续请求,直到所有interceptor都处理完毕,将得到的response返回。
同时每个interceptor的intercept()方法基本都遵循以下规则:
// interceptor.class 的子类
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//1 Request阶段,该拦截器在Request阶段负责做的事情
//2 调用RealInterceptorChain.proceed(),其实是在递归调用下一个拦截器的intercept()方法
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, httpCodec, connection);
//3 Response阶段,完成了该拦截器在Response阶段负责做的事情,然后返回到上一层的拦截器。
return response;
}
}
也就是说对于每个Request按照顺序正向一步步对其进行包装处理。而对于Response则是逆向处理的。而各个拦截器的顺序已经在getResponseWithInterceptorChain()中按照add的先后顺序排列好了。接下来按照其顺序一个个分析各个拦截器。
2.5.1 RetryAndFollowUpInterceptor
这个拦截器主要负责失败重试和重定向
public final class RetryAndFollowUpInterceptor implements Interceptor {
private static final int MAX_FOLLOW_UPS = 20;
...
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
...
// 重定向次数
int followUpCount = 0;
Response priorResponse = null;
while (true) {
...
Response response = null;
boolean releaseConnection = true;
try {
// 继续执行下一个Interceptor,即BridgeInterceptor,获取响应
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
// 抛出异常,则检测连接是否还可以继续。可以的话就重新进行请求
if (!recover(e.getLastConnectException(), false, request)) {
throw e.getLastConnectException();
}
releaseConnection = false;
continue;
} catch (IOException e) {
// 和服务端建立连接失败
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
} finally {
//检测到其他未知异常,则释放连接和资源
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
//构建响应体,这个响应体的body为空。
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
//获取重定向的请求
Request followUp = followUpRequest(response);
// 如果重定向请求为null,直接返回结果
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
return response;
}
...
//重定向的次数不能超过20次
if (++followUpCount > MAX_FOLLOW_UPS) {
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
...
// 将请求重新赋值为重定向的请求,继续循环
request = followUp;
priorResponse = response;
}
}
}
这个拦截器的整个流程可以概括为如下过程:
① 执行下一个Interceptor,即BridgeInterceptor
② 抛出异常,则检测连接是否还可以继续,如果可以的话就进行重试
③ 根据响应码处理请求,返回Request不为空时则进行重定向处理,重定向的次数不能超过20次。如果需要重定向则继续循环请求。
2.5.2 BridgeInterceptor
这个拦截器负责把用户构造的请求转换为发送给服务器的请求,把服务器返回的响应转换为对用户友好的响应。 转换的过程就是添加一些服务端需要的header信息。
public final class BridgeInterceptor implements Interceptor {
private final CookieJar cookieJar;
@Override public Response intercept(Chain chain) throws IOException {
// 获取用户请求
Request userRequest = chain.request();
// 真正发送的网络请求构建者,也就是对前面RetryAndFollowUpInterceptor传来的请求进行包装后的请求
Request.Builder requestBuilder = userRequest.newBuilder();
// 对请求头进行一些设置
// 包括:Content-Type、Content-Length、Transfer-Encoding、Host、Connection、Accept-Encoding
// Cookie、User-Agent
...
// 执行下一个拦截器,把处理过后的请求放进去
Response networkResponse = chain.proceed(requestBuilder.build());
...
// 对获取的响应进行处理
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
//判断服务器是否支持gzip压缩,如果支持,则将压缩提交给Okio库来处理
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
}
// 返回处理过后的响应
return responseBuilder.build();
}
}
2.5.3 CacheInterceptor
这个拦截器负责处理与缓存相关的事情,在这里读取和更新缓存。网络请求到了这个拦截器,会先查找有没对应的缓存,有就直接返回缓存中数据。如果没有,就接着调用下一个拦截器来获取响应,并将响应存到缓存中,方便下一次使用。
public final class CacheInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
// 读取候选缓存
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
...
// 创建缓存策略,强制缓存、对比缓存等
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
...
// 根据策略,不使用网络,又没有缓存的直接报错,并返回错误码504。
if (networkRequest == null && cacheResponse == null) {
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
}
// 根据策略,不使用网络,有缓存的直接返回。
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
// 前面两个都没有返回,继续执行下一个Interceptor,即ConnectInterceptor。
networkResponse = chain.proceed(networkRequest);
} finally {
//如果发生IO异常,则释放掉缓存
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
// 接收到网络结果,如果响应code式304,则使用缓存,返回缓存结果。
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
Response response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis())
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
...
return response;
} else {
closeQuietly(cacheResponse.body());
}
}
// 读取网络结果。
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
// 对数据进行缓存。
if (cache != null) {
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
}
}
}
// 返回网络读取的结果。
return response;
}
}
2.5.4 ConnectInterceptor
该拦截器主要作用是给网络请求提供一个连接,为下一个拦截器做准备。
public final class ConnectInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
boolean doExtensiveHealthChecks = !request.method().equals("GET");
// 获取一个http编解码器,创建输出流。
HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);
// 获取一个连接对象,负责发起与服务器的连接
RealConnection connection = streamAllocation.connection();
// 执行下一个拦截器
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
}
2.5.5 CallServerInterceptor
这是最后一个拦截器,负责真正与服务器进行交互。
public final class CallServerInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
//这些对象在前面的Interceptor都已经创建完毕
RealInterceptorChain realChain = (RealInterceptorChain) chain;
HttpCodec httpCodec = realChain.httpStream();
StreamAllocation streamAllocation = realChain.streamAllocation();
RealConnection connection = (RealConnection) realChain.connection();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
// 写入请求头
httpCodec.writeRequestHeaders(request);
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
httpCodec.flushRequest();
responseBuilder = httpCodec.readResponseHeaders(true);
}
// 写入请求体
if (responseBuilder == null) {
// Write the request body if the "Expect: 100-continue" expectation was met.
Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
} else if (!connection.isMultiplexed()) {
// If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection from
// being reused. Otherwise we're still obligated to transmit the request body to leave the
// connection in a consistent state.
streamAllocation.noNewStreams();
}
}
// 发起网络请求
httpCodec.finishRequest();
// 读取响应头
if (responseBuilder == null) {
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
// 读取响应体
int 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 = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
...
// 返回网络响应结果
return response;
}
}
这个拦截器将前面准备好的请求头和请求体整合好,向服务器发起网络请求,并获取响应头和响应体返回。
整个请求响应过程到此告一段落。
网友评论