OKhttp是 Square 公司贡献的一个android 网络框架库,支持http和http2的JAVA框架,是时下最流行的框架,不客气的说是一定要会的,大厂必备。重要指数5颗星
一 Okhttp基本实用 (掌握最基础的才能进一步深入)
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().get().url("XXXXXX").addHeader("xxx","xxx").build();
Response response=client.newCall(request).execute();
说明:上面的代码是OKHTTP的基本用法用来同步请求网络数据,这样基本就入门了,可用用来请求接口获取回调了.Android基本不会实用excute,android网络请求必须放在后台,所以实际中我们一般使用一下方法
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().url("http://www.baidu.com").addHeader("xxxx","xxx").get().build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
用异步的方法来调用接口。
二 基本的调用流程的分析
从发送网络的接口看起 Request拼接好请求的URL之后,通过newCall方法来封装,这个newCall具体是什么呢?我们来看一下
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
newCall实际上是创建了一个RealCall的对象封装了我们的Request。OKHTTP对他的说明是准备好在将来的需要的时候用来执行的这么一个类。看名字也知道了,真正的请求是在RealCall中 所以我们看下RealCall具体是什么
可以看到创建了RealCall 并且 给Call添加了一个eventListener。这里记住orginalRequest。为什么叫这个,是因为和okhttp的网络请求链有关这个是初始的。这个eventListener是用来监听和记录网络连接的状态的。所以对于OKHTTP RealCall这个类是很重要的。Okhttp有异步和同步两种发送请求的方式,我们先来看简单的同步请求的方式
可以看到这里有eventlistener迎来发送请求的状态。这里的一个核心方法dispatcher.excuted 用这个来执行真正的请求,就是一个转发的,这个dispather是什么呢,其实就是封装了线程池专门用来做请求的。我们具体看看这个类的方法和属性
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
/** Executes calls. Created lazily. */
private @Nullable ExecutorService executorService;
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
private int maxRequests = 64;
这个属性其实挺明白的,okhttp最大同时执行64个请求
private int maxRequestsPerHost = 5
最大支持5个不同的HOST节点
/** Executes calls. Created lazily. */
private @Nullable ExecutorService executorService;
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
创建一个线程池,创建3个队列,分别是等待中的队列 ,正在执行的同步队列,正在执行的异步队列 这三个队列很重要
通过单例创建的一个线程池。好了大体看了下,知道这个类就是封装了线程池用来做请求的,接下来我们看下他的excute的方法具体做了什么
简单的把call对象加入到了同步运行队列中
那么异步的请求做了什么呢?
异步请求同样会调用dispatcher类,并且把原来的callback封装成一个AsyncCall的类
这个类是干什么的?进去看一下
他其实继承了一个实现runnable的抽象类在run方法中间调用了抽象方法excute()所以我们直接看Anycall的excute方法做了什么
@Override protected void execute() {
boolean signalledCallback = false;
timeout.enter();
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) {
e = timeoutExit(e);
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
可以看到一个熟悉的方法getResponseWithInterceptorChain()这个方法同步和异步都调用了,这个是OKhttp的核心方法,集中处理请求和响应。这个我们在后面在说。这里基本上就是拿到数据之后就回调了。知道了这个Anycall之后在回到dispatcher类中看看具体的equeue()
跟同步调用差不多,往运行的异步准备队列中加数据同时执行
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
这个方法还是很简单的,遍历准备执行的队列,从中拿数据,如果运行的队列没有满的话,加入到运行的队列中。最好用一个for循环执行请求,并检查运行中的队列数据的执行状态并执行响应的回调。
调用AsyncCall的executeOn方法,通过线程池来执行对应的execute()方法运行起来。这样就跟上面的类一一对应起来了。基本的调用就结束了,简单点说就是封装了请求对象,通过线程池来分发执行。通过拦截器链来统一处理请求和响应
三 重点拦截器
在介绍拦截期之前我们来说说okhttpclient初始化的时候都做了些什么。
okhttp的初始化是调用内部类Builder来初始化的,是一个很典型的构造器的模式,Request也是这种模式。这就说明他们的属性有很多,我们一一来看一下。
Dispatcher dispatcher;
@Nullable Proxy proxy;
List<Protocol> protocols;
List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors = new ArrayList<>();
final List<Interceptor> networkInterceptors = new ArrayList<>();
EventListener.Factory eventListenerFactory;
ProxySelector proxySelector;
CookieJar cookieJar;
@Nullable Cache cache;
@Nullable InternalCache internalCache;
SocketFactory socketFactory;
@Nullable SSLSocketFactory sslSocketFactory;
@Nullable CertificateChainCleaner certificateChainCleaner;
HostnameVerifier hostnameVerifier;
CertificatePinner certificatePinner;
Authenticator proxyAuthenticator;
Authenticator authenticator;
ConnectionPool connectionPool;
Dns dns;
boolean followSslRedirects;
boolean followRedirects;
boolean retryOnConnectionFailure;
int callTimeout;
int connectTimeout;
int readTimeout;
int writeTimeout;
int pingInterval;
Dispatcher 就是一个线程的调取类之前介绍过来
Proxy是一个代理 类似VPN 做转发
List<Protocol> 是一个支持协议版本的集合,比如HTTP1.0 1.1 2.0
List<ConnectionSpec> 是HTTPS 验证的套件的配置 RSA AES HASH算法
List<Interceptor>拦截器的列表
eventlister创建listener的监听和统计的
Cookiejar 用来实现cookie支持的默认没有实现需要我们自己实现 是一个借口自己实现savefromresponse 和 loadfromrequest方法内容
Cache 缓存
SocketFactory 创建socket工厂
sslSocketFactory 创建ssl的工厂 分开 tcp和SSL是不同的东西所以要分开 TCP是三次握手 SSL是密钥交换等过程
CertificateChainCleaner SSL证书的整理
HostnameVerifier 主机名验证 给HTTPS用的 验证服务器的HOST
CertificatePinner 用来做HTTPS的自签名的 重点啊因为这个可能我们用的比较多 本地证书同服务器证书对比 非常常用牢记,很方便还可以防止代理抓包,因为证书的公钥信息订死了,但是缺点,服务器证书不能改,改了就不通过了
Authenticator 做授权的时候要用的,权限不足的时候返回401等,OKHTTP会拦截,如果配置这个那么遇到这个错会自动执行里面的方法,用处token过期的时候可以用这个重新拿新token传递过去。主要是加载请求头Authenticator中 这个也是非常重要的,经常要用
ConnectionPool 拦截池 缓存链接的引用同线程池查到不
DNS 域名解析服务器的配置
followSslRedirects&followRedirects followRedirects302/301跳转 设置是不是跳转。默认跳转 followSslRedirects HTTP/https互跳转是不是要跳
retryOnConnectionFailure 失败是否重连
剩下的就是一些常规的设置了
pingInterval 针对websocket的 对心跳包 长链接的 间隔时间
上面的说明完了之后就是重点的拦截器链的解析了 绝对的核心
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);
}
这块是做什么呢,其实但看还是挺简单的,就是创建一个拦截器的集合然后把自己实现的拦截器和框架默认的几个拦截器添加进去,最后生成一个链的拦截器RealinterceptorChain,这个链的作用就是我发发送请求的每一步都可以对当前请求做一些处理再传递给下一步,然后我最终从Callserver拦截器拿到返回的数据之后,从后往前再返回来的没一个步也都可以对当前的返回数据做处理,所以叫做链,互相之间都是咬颌的。
其中每个链的最重要的方法就是Proceed方法用来传递给下一个
接下来分析OKhttp自带的几个拦截器,都是很重要的
RetryAndFollowUpInterceptor
重试和重定向拦截器
我们直接看拦截器里面的Intercept方法,每个拦截器都是自己实现里面的方法,通过拦截器链来调用
这个拦截器创建了一个很重要的类StreamAllocation OKhttp有三个很重要的概念 Connection Call StreamAllocation
这个类保存了连接的response和request对,用来Connecttion请求的时候用的,一个connecttion可能有多个Stream,因为可能包含重定向
{
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
throw e.getFirstConnectException();
}
releaseConnection = false;
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
// Attach the prior response if it exists. Such responses never have a body.
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
Request followUp;
try {
followUp = followUpRequest(response, streamAllocation.route());
} catch (IOException e) {
streamAllocation.release();
throw e;
}
if (followUp == null) {
streamAllocation.release();
return response;
}
closeQuietly(response.body());
if (++followUpCount > MAX_FOLLOW_UPS) {
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
if (followUp.body() instanceof UnrepeatableRequestBody) {
streamAllocation.release();
throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
}
if (!sameConnection(response, followUp.url())) {
streamAllocation.release();
streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(followUp.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
} else if (streamAllocation.codec() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
request = followUp;
priorResponse = response;
}
主要代码就是这个while循环中,里面对报错异常会继续循环,会对返回的状态码进行判断是否需要重定向师傅需要验证如下图所示
/**
* Figures out the HTTP request to make in response to receiving {@code userResponse}. This will
* either add authentication headers, follow redirects or handle a client request timeout. If a
* follow-up is either unnecessary or not applicable, this returns null.
*/
private Request followUpRequest(Response userResponse, Route route) throws IOException {
if (userResponse == null) throw new IllegalStateException();
int responseCode = userResponse.code();
final String method = userResponse.request().method();
switch (responseCode) {
case HTTP_PROXY_AUTH:
Proxy selectedProxy = route != null
? route.proxy()
: client.proxy();
if (selectedProxy.type() != Proxy.Type.HTTP) {
throw new ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy");
}
return client.proxyAuthenticator().authenticate(route, userResponse);
case HTTP_UNAUTHORIZED:
return client.authenticator().authenticate(route, userResponse);
case HTTP_PERM_REDIRECT:
case HTTP_TEMP_REDIRECT:
// "If the 307 or 308 status code is received in response to a request other than GET
// or HEAD, the user agent MUST NOT automatically redirect the request"
if (!method.equals("GET") && !method.equals("HEAD")) {
return null;
}
// fall-through
case HTTP_MULT_CHOICE:
case HTTP_MOVED_PERM:
case HTTP_MOVED_TEMP:
case HTTP_SEE_OTHER:
// Does the client allow redirects?
if (!client.followRedirects()) return null;
String location = userResponse.header("Location");
if (location == null) return null;
HttpUrl url = userResponse.request().url().resolve(location);
// Don't follow redirects to unsupported protocols.
if (url == null) return null;
// If configured, don't follow redirects between SSL and non-SSL.
boolean sameScheme = url.scheme().equals(userResponse.request().url().scheme());
if (!sameScheme && !client.followSslRedirects()) return null;
// Most redirects don't include a request body.
Request.Builder requestBuilder = userResponse.request().newBuilder();
if (HttpMethod.permitsRequestBody(method)) {
final boolean maintainBody = HttpMethod.redirectsWithBody(method);
if (HttpMethod.redirectsToGet(method)) {
requestBuilder.method("GET", null);
} else {
RequestBody requestBody = maintainBody ? userResponse.request().body() : null;
requestBuilder.method(method, requestBody);
}
if (!maintainBody) {
requestBuilder.removeHeader("Transfer-Encoding");
requestBuilder.removeHeader("Content-Length");
requestBuilder.removeHeader("Content-Type");
}
}
// When redirecting across hosts, drop all authentication headers. This
// is potentially annoying to the application layer since they have no
// way to retain them.
if (!sameConnection(userResponse, url)) {
requestBuilder.removeHeader("Authorization");
}
return requestBuilder.url(url).build();
case HTTP_CLIENT_TIMEOUT:
// 408's are rare in practice, but some servers like HAProxy use this response code. The
// spec says that we may repeat the request without modifications. Modern browsers also
// repeat the request (even non-idempotent ones.)
if (!client.retryOnConnectionFailure()) {
// The application layer has directed us not to retry the request.
return null;
}
if (userResponse.request().body() instanceof UnrepeatableRequestBody) {
return null;
}
if (userResponse.priorResponse() != null
&& userResponse.priorResponse().code() == HTTP_CLIENT_TIMEOUT) {
// We attempted to retry and got another timeout. Give up.
return null;
}
if (retryAfter(userResponse, 0) > 0) {
return null;
}
return userResponse.request();
case HTTP_UNAVAILABLE:
if (userResponse.priorResponse() != null
&& userResponse.priorResponse().code() == HTTP_UNAVAILABLE) {
// We attempted to retry and got another timeout. Give up.
return null;
}
if (retryAfter(userResponse, Integer.MAX_VALUE) == 0) {
// specifically received an instruction to retry without delay
return userResponse.request();
}
return null;
default:
return null;
}
}
基本上就是通过返回的状态码执行相应的操作,对响应的状态码不熟悉的可以去百度参考下,40x验证不通过的操作,这个就用到了之前OKhttp基础属性的那块知识了,30X跳转重定向,还有包括一些timeout和服务器不可达的处理操作。都处理完毕之后就会返回真正的信息了,在我们没有自己设置拦截器的情况下,如果设置了还可以对这个返回进行操作,比如我们常用的一些LOG拦截器啊等等。这是第一个拦截器逻辑很清楚明白
BridegeInterceptor
顾名思义,桥接拦截器,这个拦截器会有一个cookiejar的参数,这个参数我们之前说到了,系统默认是没有实现的,我们需要通过自己来实现,这个就是用来存取COOKIE用的,所以基本上这个拦截器应该会跟请求头或者响应头来打交道我们看看是不是 ,还是直接看intercep方法里面的内容
@Override public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
if (body != null) {
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");
}
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
Response networkResponse = chain.proceed(requestBuilder.build());
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
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);
String contentType = networkResponse.header("Content-Type");
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}
return responseBuilder.build();
}
很明显了,是对header进行增强操作和cookies的存储,需要说一点的是最后一个if判断代码块,是对GZIP的支持,OKHTTP默认提供的,这样可以减少带宽。这个基本就是这个拦截器干的事情了
CacheInterceptor
缓存相关的拦截器设置,这个拦截器需要一个参数InternalCache这个类的文档说这个是OKHTTP内部的一个接口,我们使用应用的时候不要自己去实现这个接口。好吧那我们听话一点就不去管他了。不管他的话,创建这个拦截器的时候会走拦截器内部的具体的缓存,这个实际意义上就是如果写了,就表明我们自己写了缓存的实现,OKHTTP不推荐这种。啰嗦了,反正就是用OKHTTP自带的就行了。就是默认的CacheStragegy来事项缓存策略
基本的流程就是断网了且缓存不足返回一个服务器不可达的状态码,有缓存不需要网络的情况下,直接走缓存,网络返回的和本地的缓存一样,直接返回缓存,其他情况走网络,然后把网络数据重新存到CACHE中。
CacheStragegy中具体的实现通过缓存中的HEAD信息中拿取缓存的信息,跟现在的时间等信息进行比对。然后有缓存正确的话,直接就返回了,不做其他处理了。具体的实现很复杂,内部好像还是Lurcache的使用这里不多说了
ConnectInterceptor
链接拦截器
@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);
}
代码只有这么几行,看这很简单,但是非常重要。里面HttpCodec和RealConnection都是核心的实现
HttpCodec是对请求就行编码对返回的信息进行解码用的。具体我们进去看一看
try {
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
throw new RouteException(e);
}
具体的就是这段代码,找到健康的链接,这个是什么意思?什么叫健康的链接?简单点说就是找到一个已有的能用的链接,内部还是挺复杂的,最后调用的是OKIO来创建SOCKET进行TCP链接。
findHealthyConnect 会调用findConnect方法,最后会执行一个核心的方法
// Do TCP + TLS handshakes. This is a blocking operation.
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
routeDatabase().connected(result.route());
看注释这里是进行TCP和TLS会话握手的地方,TCP三次链接握手 HTTPS的链接握手不知道的小伙伴可以去百度了解一下,对看源码很有帮助。这个里面具体的逻辑蛮复杂的我不是很能看懂所以不说了哈哈
CallserverInterceptor
这个是拦截器中最后的一个了,看完这个基本也就结束了,真是长啊。这个拦截器主要就是跟服务器沟通的了,通过SOCKET读写数据到服务器。
httpCodec.writeRequestHeaders(request);
这个httpCodec上面说过了对请求和响应的编码和解码,有两个实现类 http1的实现和http2的实现,这个write就是把请求的信息通过socket写成HTTP请求报文的样式,包含请求头啊,请求行,请求内容
responseBuilder = httpCodec.readResponseHeaders(false);
跟上面的一样不过是用来读取服务器的内容转换为响应报文获取响应的数据,并把响应的内容返回给前一个链做处理,基本上就是这个逻辑。
结束
到此OKHTTP的整体流程就基本结束了,看OKHTTP的源码有助于对HTTP和HTTPS的实现的理解。还可以帮助我们更好的在应用层进行功能的开发,其他的一些功能我会抽时间来补充,比如websocket的补充,networkinterceptor的使用和功能等。