基本使用:
依赖:
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
使用:
String url = "http://wwww.baidu.com";
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
//Sync 同步的方式会引起线程阻塞,不允许在主线程使用
Response response = client.newCall(request).execute(); //Catch IOException
//Async
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {}
@Override
public void onResponse(Call call, Response response) throws IOException {}
});
请求基本流程:
1.Request.Builder—>Request—>Call(RealCall)
2.Call加入队列—>Interceptor.Chain处理—>Response
具体过程:
Reques#Builder主要成员变量:
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Map<Class<?>, Object> tags;
Request生成Call: Call call = client.newCall(request):
//ClassName = OkHttpClient
@Override
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
看看RealCall的成员变量和主要方法有什么:
final class RealCall implements Call {
final OkHttpClient client;
private Transmitter transmitter;
final Request originalRequest;
final boolean forWebSocket;
private boolean executed;
@Override
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false);
}
@Override
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();
transmitter.callStart();
try {
//同步处理请求将realCall加入一个队列,this = Realcall
client.dispatcher().executed(this);
//在当前线程调用来拦截器链处理请求
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this); //this = Realcall,Realcall出队
}
}
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
//异步处理请求将一个AsyncCall加入队列
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
@Override
public void cancel();
Response getResponseWithInterceptorChain()
//RealCall内部类AsynCall专门用来处理异步请求,封装了realCall和回调接口,使执行过程切换到其他线程
final class AsyncCall extends NamedRunnable { //间接实现了Runnable接口
private final Callback responseCallback;
void executeOn(ExecutorService executorService);
@Override
public final void run() {
execute();
}
@Override
protected void execute() { //与RealCall基本相同的逻辑,都是用责任链处理Call返回Response
try {
//调用来拦截器链处理请求
Response response = getResponseWithInterceptorChain();
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
responseCallback.onFailure(RealCall.this, e);
} finally {
client.dispatcher().finished(this); //AsynCall出队
}
}
}
}
可见同步处理请求和异步处理请求的流程大致都相同,都是先把请求加入队列
,然后调用getResponseWithInterceptorChain方法用拦截器链处理
,下面分开来看两个过程:
将同步或异步的请求加入Dispatcher中的任务队列:
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<>(); //同步正在执行队列
//获取一个线程池,这个线程池没有核心线程,线程数量没有限制,空闲60s就会回收*/
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;
}
synchronized void executed(RealCall call) { //分发器执行就是把Realcall加入同步正在执行队列中去
runningSyncCalls.add(call);
}
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call); //先加入异步准备队列中
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
promoteAndExecute();
}
private boolean promoteAndExecute() { //省略部分逻辑
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) { //遍历异步准备队列
if (runningAsyncCalls.size() >= maxRequests) break; //正在处理的请求数达到最大,跳出循环
executableCalls.add(asyncCall); //否则加入正在执行队列
runningAsyncCalls.add(asyncCall);
}
for (int i = 0, size = executableCalls.size(); i < size; i++) { //遍历可执行Asyncall队列
AsyncCall asyncCall = executableCalls.get(i);
//依次将这些Asyncall交给线程池处理(AsnyCall实现了Runnable接口)
asyncCall.executeOn(executorService());
}
isRunning = runningCallsCount() > 0;
return isRunning;
}
}
可以看到Dispatcher的功能非常简单,就是维护三个队列,规划异步请求的执行顺序
接下来看创建拦截器链处理请求的方法:
//ClassName = RealCall
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
//用户自定义的拦截器
interceptors.addAll(client.interceptors());
//请求失败和重定向拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
//构建请求和构建相应的拦截器
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));
//用List<Interceptor>可以构造一个对象
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//用RealInterceptorChain处理实际请求
return chain.proceed(originalRequest);
}
OkHttpClient可以通过两种方式添加拦截器:·
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(xxx)
.addNetworkInterceptor(xxx)
由源码可知,各个拦截器的执行顺序为:
自定义普通拦截器,retry,bridge,cache,connect,自定义网络拦截器,callServer拦截器
拦截器链调用过程:
//ClassName = RealInterceptorChain
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException { //省略部分逻辑
//index表示当前拦截器在连接器链中的index,拦截器链处理请求前要先用后面的拦截器构建一条新的拦截器链;
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
//获取当前拦截器;
Interceptor interceptor = interceptors.get(index);
//用当前拦截器处理请求(请求包含在拦截器链next.request中),next为后续所有拦截器组成的链
Response response = interceptor.intercept(next);
}
拦截器的intercept方法使用的参数是chain,这样设计的目的是,将是否调用后续的拦截器的控制权交给拦截器本身;如果无需后续拦截器处理,由当前拦截器生成Response返回,如果需要后续拦截器处理,则由当前拦截器调用chain.proceed()
5个默认拦截器:
看拦截器代码首先要找到 realChain.proceed(…),这句代码会调用后续拦截器处理,把Request转化为Response,这句代码之前的逻辑都用来处理Request,之后的代码都用来处理Response。
重定向拦截器:
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
//这里新建了一个流对象,负责数据传输
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
int followUpCount = 0;
Response priorResponse = null;
while (true) {
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
//这里调用后续拦截器处理request,是request和respone的分界线
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (Exception e) {
//...
releaseConnection = false;
continue;
} finally {
// 走到这里说明请求成功了,释放资源
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
...
Request followUp;
try {
//follow就是重定向之后产生的新的request;若要获取正确的相应,需要重新进行一次请求
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?");
}
//走到这里,由于重定向或请求失败,需要重新请求
//这里用follow替换了request,做while循环
request = followUp;
priorResponse = response;
}
}
BridgeInterceptor: 主要负责添加Http头部,和处理gzip等
public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
...
//为Request添加Head
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
...
Response networkResponse = chain.proceed(requestBuilder.build());
//接收返回的cookie
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
//处理gzip
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();
}
缓存拦截器:
//ClassName = CacheInterceptor
@Override
public Response intercept(Chain chain) throws IOException {
//cache不为空的话直接从缓存中获取Response
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest; //== null if 网络不可用或不需要
Response cacheResponse = strategy.cacheResponse; //== null if 缓存为空
if (cache != null) {
cache.trackResponse(strategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
// 如果网络不可用,且缓存不可用,本地构造一个失败的响应并返回;
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;
networkResponse = chain.proceed(networkRequest);
// 此时获取了网络调用产生的响应
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();
networkResponse.body().close();
cache.trackConditionalCacheHit();
//更新缓存并返回响应结果
cache.update(cacheResponse, response);
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)) {
// Offer this request to the cache.
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
return response;
}
1.发送请求前:
网络缓存都不可用,返回一个失败的响应;
网络不可用,缓存可用,从缓存获取;
网络可用,缓存不可用,调用后续的拦截器处理请求;
2.得到远端数据之后:
检查缓存开关是否开启,可用则更新缓存结果
连接池拦截器:
ConnectInterceptor主要是从连接池去取连接,http请求要先3次握手才能建立连接,复用连接可以免去握手的时间。
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 httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
//
public HttpCodec newStream(
...
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);
}
}
//获取连接的方法
private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
int writeTimeout, int pingIntervalMillis, boolean connectionRetryEnabled,
boolean doExtensiveHealthChecks) throws IOException {
while (true) {
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
pingIntervalMillis, connectionRetryEnabled);
// If this is a brand new connection, we can skip the extensive health checks.
synchronized (connectionPool) {
if (candidate.successCount == 0) {
return candidate;
}
}
if (!candidate.isHealthy(doExtensiveHealthChecks)) {
noNewStreams();
continue;
}
return candidate;
}
}
CallServerInterceptor:最后一个拦截器,它向服务器发起真正的网络请求
public Response intercept(Chain chain) throws IOException {
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();
realChain.eventListener().requestHeadersStart(realChain.call());
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Response.Builder responseBuilder = null;
//...
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis()) //获取response
.build();
code = response.code();
if(code == 100) {
//重试一次
responseBuilder = httpCodec.readResponseHeaders(false);
response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
if(code == 101){
...
}
if(code == 204 || code == 205){
throw new ProtocolException(xxxx);
}
return response;
}
https://blog.csdn.net/asffghfgfghfg1556/article/details/80787240