Okhttp系列文章:
你想要的系列:网络请求框架OkHttp3全解系列 - (一)OkHttp的基本使用
你想要的系列:网络请求框架OkHttp3全解系列 - (二)OkHttp的工作流程分析
你想要的系列:网络请求框架OkHttp3全解系列 - (三)拦截器详解1:重试重定向、桥、缓存(重点)
你想要的系列:网络请求框架OkHttp3全解系列 - (四)拦截器详解2:连接、请求服务(重点)

在本系列的上一篇文章中,我们学习了OkHttp的基本用法,体验了这个网络加载框架的强大功能,以及它非常简便的API。还没有看过上一篇文章的朋友,建议先去阅读 网络请求框架OkHttp3全解系列 - (一)OkHttp的基本使用 。

如果我们想要进行get请求,那么使用少量的代码就能实现,如下所示:

        OkHttpClient httpClient = new OkHttpClient();String url = "https://www.baidu.com/";Request getRequest = new Request.Builder().url(url).get().build();Call call = httpClient.newCall(getRequest);call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, Response response) throws IOException {}});

看起来很简洁的代码,实际是OkHttp在背后帮我们默默执行了成吨的工作。

知其然也要知其所以然。那么这篇我们就来解析一下OkHttp的源码,看看它在这些简单用法的背后,到底执行了多么复杂的工作。

请求的创建

以上面get请求的代码步骤分析,那么先分析OkHttpClient实例的创建。
在上一篇中,提到OkHttpClient实例化可以直接创建,也可以使用Builder建造者模式进行配置然后build()即可。直接创建其实就是使用了默认的配置。其构造方法如下:

  public OkHttpClient() {this(new Builder());}OkHttpClient(Builder builder) {this.dispatcher = builder.dispatcher;//调度器,用于控制并发的请求。内部保存同步和异步请求的call,并使用线程池处理异步请求。this.proxy = builder.proxy;//代理设置this.protocols = builder.protocols;//http协议this.connectionSpecs = builder.connectionSpecs;//连接配置this.interceptors = Util.immutableList(builder.interceptors);//全局拦截器this.networkInterceptors = Util.immutableList(builder.networkInterceptors);//网络拦截器this.eventListenerFactory = builder.eventListenerFactory;//请求的监听器的创建工厂this.proxySelector = builder.proxySelector;//代理选择器this.cookieJar = builder.cookieJar;//cookie,默认没有cookie:CookieJar.NO_COOKIESthis.cache = builder.cache;//网络缓存设置this.internalCache = builder.internalCache;//内部使用的缓存接口this.socketFactory = builder.socketFactory;//socket工厂boolean isTLS = false;for (ConnectionSpec spec : connectionSpecs) {isTLS = isTLS || spec.isTls();}if (builder.sslSocketFactory != null || !isTLS) {this.sslSocketFactory = builder.sslSocketFactory;this.certificateChainCleaner = builder.certificateChainCleaner;} else {X509TrustManager trustManager = Util.platformTrustManager();this.sslSocketFactory = newSslSocketFactory(trustManager);this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);}if (sslSocketFactory != null) {Platform.get().configureSslSocketFactory(sslSocketFactory);}this.hostnameVerifier = builder.hostnameVerifier;this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(certificateChainCleaner);this.proxyAuthenticator = builder.proxyAuthenticator;this.authenticator = builder.authenticator;//以上几个是安全相关设置this.connectionPool = builder.connectionPool;//连接池this.dns = builder.dns;//域名解析系统this.followSslRedirects = builder.followSslRedirects;//ssl重定向this.followRedirects = builder.followRedirects;//重定向this.retryOnConnectionFailure = builder.retryOnConnectionFailure;//连接失败时是否重试this.callTimeout = builder.callTimeout;this.connectTimeout = builder.connectTimeout;this.readTimeout = builder.readTimeout;this.writeTimeout = builder.writeTimeout;//几个超时设置this.pingInterval = builder.pingInterval;//ping间隔时间//拦截器不能是nullif (interceptors.contains(null)) {throw new IllegalStateException("Null interceptor: " + interceptors);}if (networkInterceptors.contains(null)) {throw new IllegalStateException("Null network interceptor: " + networkInterceptors);}}public static final class Builder {...public Builder() {//默认的配置dispatcher = new Dispatcher();protocols = DEFAULT_PROTOCOLS;connectionSpecs = DEFAULT_CONNECTION_SPECS;eventListenerFactory = EventListener.factory(EventListener.NONE);proxySelector = ProxySelector.getDefault();if (proxySelector == null) {proxySelector = new NullProxySelector();}cookieJar = CookieJar.NO_COOKIES;socketFactory = SocketFactory.getDefault();hostnameVerifier = OkHostnameVerifier.INSTANCE;certificatePinner = CertificatePinner.DEFAULT;proxyAuthenticator = Authenticator.NONE;authenticator = Authenticator.NONE;connectionPool = new ConnectionPool();dns = Dns.SYSTEM;followSslRedirects = true;followRedirects = true;retryOnConnectionFailure = true;callTimeout = 0;connectTimeout = 10_000;readTimeout = 10_000;writeTimeout = 10_000;pingInterval = 0;}
...}

直接创建OkHttpClient实例,配置项就是Builder构造方法中默认值。 可见配置项是非常多的,包括上一篇中已经使用过的超时设置、拦截器。

接着看Request的创建,也是使用建造者模式:

    public Builder() {this.method = "GET";this.headers = new Headers.Builder();}public Builder get() {return method("GET", null);}public Builder post(RequestBody body) {return method("POST", body);}public Builder method(String method, @Nullable RequestBody body) {if (method == null) throw new NullPointerException("method == null");if (method.length() == 0) throw new IllegalArgumentException("method.length() == 0");if (body != null && !HttpMethod.permitsRequestBody(method)) {throw new IllegalArgumentException("method " + method + " must not have a request body.");}if (body == null && HttpMethod.requiresRequestBody(method)) {throw new IllegalArgumentException("method " + method + " must have a request body.");}this.method = method;this.body = body;return this;}public Builder addHeader(String name, String value) {headers.add(name, value);return this;}public Builder url(String url) {if (url == null) throw new NullPointerException("url == null");// Silently replace web socket URLs with HTTP URLs.if (url.regionMatches(true, 0, "ws:", 0, 3)) {url = "http:" + url.substring(3);} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {url = "https:" + url.substring(4);}return url(HttpUrl.get(url));}public Request build() {if (url == null) throw new IllegalStateException("url == null");return new Request(this);}

注意到get()和post(RequestBody body)都是对method方法的包装,method方法内部对请求方式和请求体进行了校验,比如get请求不能有请求体、post请求必须要请求体等。其他比较好理解,不再赘述。

接着看HttpClient的newCall方法:

  @Override public Call newCall(Request request) {return RealCall.newRealCall(this, request, false /* for web socket */);}

跟进RealCall的newRealCall方法:

  static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {// Safely publish the Call instance to the EventListener.RealCall call = new RealCall(client, originalRequest, forWebSocket);call.transmitter = new Transmitter(client, call);return call;}

可见HttpClient的newCall方法获得Call实际是RealCall。RealCall就是准备执行的请求,是对接口Call的实现。其内部持有OkHttpClient实例、Request实例。并且这里还创建了Transmitter给RealCall的transmitter赋值。

Transmitter意为发射器,是应用层和网络层的桥梁,在进行 连接、真正发出请求和读取响应中起到很重要的作用,看下构造方法:

  public Transmitter(OkHttpClient client, Call call) {this.client = client;this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());this.call = call;this.eventListener = client.eventListenerFactory().create(call);this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);}

Transmitter内部持有OkHttpClient、连接池、call、事件监听器。

再回头看RealCall实现的接口Call:

//  已准备要执行的请求。由于表示单个请求/响应对(流),因此无法执行两次
public interface Call extends Cloneable {...//同步请求,会阻塞Response execute() throws IOException;//异步请求void enqueue(Callback responseCallback);//取消请求,已经完成的不能取消。void cancel();boolean isExecuted();boolean isCanceled();Timeout timeout();
...interface Factory {Call newCall(Request request);}
}

主要是定义请求的执行动作和状态。RealCall对Call的具体实现,在后面执行流程中说明。

好了,请求的创建就到这里了。

请求的调度

执行分为同步和异步,这里先从 同步请求 开始分析,即RealCall的execute方法:

  @Override public Response execute() throws IOException {synchronized (this) {if (executed) throw new IllegalStateException("Already Executed");executed = true;}transmitter.timeoutEnter();//超时计时开始transmitter.callStart();//回调请求监听器的请求开始try {client.dispatcher().executed(this);//放入队列return getResponseWithInterceptorChain();//执行请求获取结果} finally {client.dispatcher().finished(this);//请求结束}}

首先判断 如果已经执行,就会抛出异常。这就是一个请求只能执行一次的原因。然后回调请求监听器的请求开始。然后调用client的调度器Dispatcher的executed方法:

  synchronized void executed(RealCall call) {runningSyncCalls.add(call);}

很简单,请求放入一个双端队列runningSyncCalls中,表示正在执行的同步请求。

然后返回了getResponseWithInterceptorChain()的结果Response,可以猜到,同步请求真正的请求流程是在getResponseWithInterceptorChain方法中
最后请求结束,会走Dispatcher的finished(Deque calls, T call)方法,:

  //结束 异步请求void finished(AsyncCall call) {//callsPerHost-1call.callsPerHost().decrementAndGet();finished(runningAsyncCalls, call);}//结束 同步请求void finished(RealCall call) {finished(runningSyncCalls, call);}//异步、同步的结束,都会走到这里:从running中移除 并 调用promoteAndExecuteprivate <T> void finished(Deque<T> calls, T call) {...synchronized (this) {//从队列中移除if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");idleCallback = this.idleCallback;}boolean isRunning = promoteAndExecute();...}

从队列中移除call,然后执行了 promoteAndExecute(),这里先不跟进去了后面会讲到。

到这里,我们知道了,同步请求走的是getResponseWithInterceptorChain()方法

我们再来看 异步请求,即RealCall的enqueue方法:

  public void enqueue(Callback responseCallback) {synchronized (this) {if (executed) throw new IllegalStateException("Already Executed");executed = true;}transmitter.callStart();//回调请求监听器的请求开始client.dispatcher().enqueue(new AsyncCall(responseCallback));//请求调度}

同样先判断是否已请求过,回调请求开始。然后调用Dispatcher的enqueue方法,参数接受的是AsyncCall,AsyncCall继承NamedRunnable,NamedRunnable实现自Runnable,即AsyncCall就是个Runnable,可以想到它是会在线程或线程池执行run方法的。run方法在AsyncCall没看到啊,实际是在在NamedRunnable中:

//知道当前线程名字的Runnable
public abstract class NamedRunnable implements Runnable {protected final String name;public NamedRunnable(String format, Object... args) {this.name = Util.format(format, args);}public final void run() {String oldName = Thread.currentThread().getName();Thread.currentThread().setName(name);try {execute();} finally {Thread.currentThread().setName(oldName);}}protected abstract void execute();
}

run调用 抽象方法execute(),execute()在AsyncCall是有实现的,这里先不看。

我们继续去看Dispatcher的enqueue方法:

  void enqueue(AsyncCall call) {synchronized (this) {//存入等待执行的队列readyAsyncCalls.add(call);// 相同host的请求,共用一个 调用计数if (!call.get().forWebSocket) {AsyncCall existingCall = findExistingCallWithHost(call.host());if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);}}promoteAndExecute();}//从 runningAsyncCalls或者readyAsyncCalls中找到相同host的请求private AsyncCall findExistingCallWithHost(String host) {for (AsyncCall existingCall : runningAsyncCalls) {if (existingCall.host().equals(host)) return existingCall;}for (AsyncCall existingCall : readyAsyncCalls) {if (existingCall.host().equals(host)) return existingCall;}return null;}

先把请求放入双端队列readyAsyncCalls中,表示等待执行的异步请求。为啥是等待执行呢?先留一个疑问。 接着从 正在执行的请求runningAsyncCalls 或 等待执行的请求readyAsyncCalls 中找到是相同host的请求,把callsPerHost重用给当前请求。callsPerHost看名字感觉像是 拥有相同host的请求的数量,并且注意到类型是AtomicInteger,声明如下:

    private volatile AtomicInteger callsPerHost = new AtomicInteger(0);

所以,相同host的请求是共享callsPerHost的,为了后面判断host并发做准备。

继续看,接着调用了promoteAndExecute(),前面看的finish方法也有调用,这里可以跟进看看了:

  //调度的核心方法:在 控制异步并发 的策略基础上,使用线程池 执行异步请求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; //最大并发数64if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; //Host最大并发数5i.remove();//从等待队列中移除asyncCall.callsPerHost().incrementAndGet();//Host并发数+1executableCalls.add(asyncCall);//加入 可执行请求 的集合runningAsyncCalls.add(asyncCall);//加入 正在执行的异步请求队列}isRunning = runningCallsCount() > 0;//正在执行的异步/同步 请求数 >0}for (int i = 0, size = executableCalls.size(); i < size; i++) {AsyncCall asyncCall = executableCalls.get(i);asyncCall.executeOn(executorService());//可执行的请求}return isRunning;}public synchronized int runningCallsCount() {return runningAsyncCalls.size() + runningSyncCalls.size();}

遍历readyAsyncCalls,先进行两个检查:正在执行的异步请求runningAsyncCalls数量大于最大并发请求数64就break,或者 相同host请求的数量大于5,就continue。如果检查都通过,就从等待队列中移除,callsPerHost自增1,放入 可执行的集合executableCalls,并添加到队列runningAsyncCalls中,表示正在执行的异步请求。
这里就解释了 异步请求等待队列的意义了,就是为了控制最大并发数的缓冲:异步请求并发数达到64、相同host的异步请求达到5,都要放入等待队列。

遍历完后 把executableCalls中的请求都走executeOn方法:

    void executeOn(ExecutorService executorService) {assert (!Thread.holdsLock(client.dispatcher()));boolean success = false;try {executorService.execute(this);//在线程池执行asyncCallsuccess = true;} catch (RejectedExecutionException e) {...transmitter.noMoreExchanges(ioException);responseCallback.onFailure(RealCall.this, ioException);//回调失败} finally {if (!success) {client.dispatcher().finished(this); //执行发生异常,结束}}}//线程池的定义public synchronized ExecutorService executorService() {if (executorService == null) {executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));}return executorService;}

executeOn方法很简单:使用类似CachedThreadPool的线程池 执行请求RealCall。如果执行失败,也会调用dispatcher的finished(Deque calls, T call)方法。

前面分析过,AsyncCall的run方法会走到execute()方法,来看下:

 protected void execute() {boolean signalledCallback = false;transmitter.timeoutEnter();//超时计时开始try {Response response = getResponseWithInterceptorChain();执行请求获取结果responseCallback.onResponse(RealCall.this, response);//回调结果} catch (IOException e) {...responseCallback.onFailure(RealCall.this, canceledException);//回调失败...} finally {client.dispatcher().finished(this);//请求结束}}

我们发现,这里和 同步请求 就很像了,同样是调用getResponseWithInterceptorChain()方法来获取结果Response,不同点是使用responseCallback把结果回调出去,最后请求结束也是调用了dispatcher的finish方法。

另外,前面说过,finish方法中也调用了promoteAndExecute()方法,说明 同步/异步 请求 结束后 也会重新调度当前的异步请求。

好了,到这里我们把 调度流程 梳理下:

  1. 发起 同步 请求后,RealCall使用Dispatcher存入runningSyncCalls,然后使用getResponseWithInterceptorChain()获取结果,最后调用Dispatcher的finish方法结束请求。
  2. 发起 异步 请求后,RealCall使用Dispatcher存入readyAsyncCalls,获得host并发数,使用promoteAndExecute()方法 在 控制异步并发 的策略基础上,使用 线程池 执行异步请求(并发控制有包括 最大并发数64、host最大并发数5)。异步请求的执行 也是使用getResponseWithInterceptorChain(),获得结果后回调出去。最后调用Dispatcher的finish方法结束请求。
  3. Dispatcher:调度器,主要是异步请求的并发控制、把异步请求放入线程池执行,实现方法是promoteAndExecute()。 promoteAndExecute()有两处调用:添加异步请求时、同步/异步请求 结束时。

请求的执行

重点来啦!

通过上面分析指导,无论同步还是异步请求,最终的执行都是在RealCall的getResponseWithInterceptorChain()方法,只不过异步请求 需要先通过Dispatcher进行并发控制和线程池处理。那么就来看看getResponseWithInterceptorChain():

  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)); //请求服务拦截器//拦截器链Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,originalRequest, this, client.connectTimeoutMillis(),client.readTimeoutMillis(), client.writeTimeoutMillis());boolean calledNoMoreExchanges = false;try {Response response = chain.proceed(originalRequest);//链 开始执行if (transmitter.isCanceled()) {closeQuietly(response);throw new IOException("Canceled");}return response;} catch (IOException e) {calledNoMoreExchanges = true;throw transmitter.noMoreExchanges(e);} finally {if (!calledNoMoreExchanges) {transmitter.noMoreExchanges(null);}}}

首先是 把

  • 应用拦截器(外部配置)client.interceptors()、
  • 重试跟进拦截器RetryAndFollowUpInterceptor、
  • 桥拦截器BridgeInterceptor、
  • 缓存拦截器CacheInterceptor、
  • 连接拦截器ConnectInterceptor、
  • 网络拦截器(外部配置)client.networkInterceptors()、
  • 请求服务拦截器CallServerInterceptor,

依次 添加到集合interceptors中。然后使用interceptors、transmitter、originalRequest等创建了拦截器链RealInterceptorChain实例,最后用proceed方法获取到请求的结果Response。

在上一篇 使用方法中有提到拦截器Interceptor,那里配置的拦截器 实际就是 应用拦截器:client.interceptors(),是最早被添加到interceptors中。那么到底 拦截器是个啥呢?chain.proceed是如何获取到结果的呢?不着急,我们先看看Interceptor类:

//拦截器
public interface Interceptor {Response intercept(Chain chain) throws IOException;//拦截器链interface Chain {Request request();//Chain的核心方法Response proceed(Request request) throws IOException;//返回请求执行的 连接. 仅网络拦截器可用; 应用拦截器就是null.@Nullable Connection connection();Call call();int connectTimeoutMillis();Chain withConnectTimeout(int timeout, TimeUnit unit);int readTimeoutMillis();Chain withReadTimeout(int timeout, TimeUnit unit);int writeTimeoutMillis();Chain withWriteTimeout(int timeout, TimeUnit unit);}
}

Interceptor是个接口类,只有一个intercept方法,参数是Chain对象。再注意到 内部接口类Chain – 拦截器链,有个proceed方法,参数是Request对象,返回值是Response,那么这个方法的实现就是请求的处理过程了。Chain的唯一实现类就是RealInterceptorChain,负责把所有拦截器串联起来,proceed方法就是串联的操作。

上述一系列的拦截器都是Interceptor的实现类,这里先贴出上一篇中实现的应用拦截器(其他拦截器的实现暂不去跟进):

        new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();String url = request.url().toString();Log.i(TAG, "intercept: proceed start: url"+ url+ ", at "+System.currentTimeMillis());Response response = chain.proceed(request);ResponseBody body = response.body();Log.i(TAG, "intercept: proceed end: url"+ url+ ", at "+System.currentTimeMillis());return response;}}

在intercept方法中我们调用chain.proceed方法获取了结果 并在前后打印了一些日志,那这个Chain实例是哪来的呢?intercept方法啥时候被调用的呢?— — 我们再回头看getResponseWithInterceptorChain方法,所有拦截器都被传入RealInterceptorChain,可以猜想到,必定是RealInterceptorChain的proceed方法内部调用了拦截器的intercept方法。 那么就来看看吧:

  @Override public Response proceed(Request request) throws IOException {return proceed(request, transmitter, exchange);}public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)throws IOException {if (index >= interceptors.size()) throw new AssertionError();calls++;// If we already have a stream, confirm that the incoming request will use it.if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)+ " must retain the same host and port");}// If we already have a stream, confirm that this is the only call to chain.proceed().if (this.exchange != null && calls > 1) {throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)+ " must call proceed() exactly once");}// Call the next interceptor in the chain.RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,index + 1, request, call, connectTimeout, readTimeout, writeTimeout);Interceptor interceptor = interceptors.get(index);Response response = interceptor.intercept(next);// Confirm that the next interceptor made its required call to chain.proceed().if (exchange != null && index + 1 < interceptors.size() && next.calls != 1) {throw new IllegalStateException("network interceptor " + interceptor+ " must call proceed() exactly once");}// Confirm that the intercepted response isn't null.if (response == null) {throw new NullPointerException("interceptor " + interceptor + " returned null");}if (response.body() == null) {throw new IllegalStateException("interceptor " + interceptor + " returned a response with no body");}return response;}

在实例化RealInterceptorChain时 index赋值是0,exchange是null,所以前面三个if都没走进去。然后获取了第一个拦截器,也就是我们配置的应用拦截器,调用了它的interceptor方法,并返回和校验了结果。这里证实了我们猜想。同时注意到,调用 应用拦截器的interceptor方法传入的参数:拦截器链实例next,next就是把index + 1而已,其他参数和当前实例是一样的。也就是说 在我们的应用拦截器中调用的是 next的proceed方法。

进一步,next的proceed方法中 同样会获取interceptors的index=1的拦截器,即RetryAndFollowUpInterceptor实例,然后调用其interceptor方法,参数是index+1即index=2的chain。跟进RetryAndFollowUpInterceptor的代码发现,interceptor方法内部也是有调用chain的proceed方法。这样就会依次传递下去,直到最后一个拦截器CallServerInterceptor。

实际上 除了最后一个拦截器CallServerInterceptor之外,所有拦截器的interceptor方法都调用了 传入 chain的proceed方法。每个拦截器在chain的proceed方法 前后 处理了自己负责的工作。例如我们的应用拦截器,在chain的proceed方法前 打印了request信息的日志,chain的proceed方法获取结果 之后 打印了response信息的日志。每个拦截器interceptor方法在 调用chain的proceed方法时 都是为了获取下一个拦截器处理的response,然后返回给上一个拦截器。

逻辑总结如下图:

这就是 okhttp执行流程的核心了,整体流程如下:

现在来总结下:

  1. 拦截器链:把原始请求 request 依次 传入到 每个拦截器。拦截器 处理后 把response 反向 依次 回传。
  2. 拦截器:可以对request进行处理,然后调用index+1的拦截器链proceed方法 获取下一个拦截器处理的结果,接着自己也可以处理这个结果,即: 处理request、chain.proceed、处理response。

不知你有没有发现,这一过程 和 公司工作生产流程 很像:

  1. 老板接到一笔订单,要求10天内生产100台电脑。
  2. 总经理拿到任务后,修改了任务和时间:8天内生产110台,这是基于 生产合格率 以及进行重工、检验、包装、运输的时间上的考量,既要保质保量,也要按时交货。
  3. 任务接着到了部门经理,部门经理先去确认了仓库中是否有足够存货,如果有就直接使用存货来交货,这样不存在任何交货风险(质量、时间);如果没有存货,那么就去要求生产线生产。
  4. 生产线按时按量生产完以后,会把生产情况 上报给部门经理,部门经理把结果总结成excel呈现给总经理,总经理则会把整个生产流程结果及各部门的配合情况,总结成PPT报告给老板。

而不同的拦截器,在网络请求这一任务中,就扮演着不同的角色。可能okhttp的作者写拦截器的灵感就来源于生活吧,哈哈。

拦截器 作用
应用拦截器 处理原始请求和最终的响应:可以添加自定义header、通用参数、参数加密、网关接入等等。
RetryAndFollowUpInterceptor 处理错误重试和重定向
BridgeInterceptor 应用层和网络层的桥接拦截器,主要工作是为请求添加cookie、添加固定的header,比如Host、Content-Length、Content-Type、User-Agent等等,然后保存响应结果的cookie,如果响应使用gzip压缩过,则还需要进行解压。
CacheInterceptor 缓存拦截器,获取缓存、更新缓存。如果命中缓存则不会发起网络请求。
ConnectInterceptor 连接拦截器,内部会维护一个连接池,负责连接复用、创建连接(三次握手等等)、释放连接以及创建连接上的socket流。
网络拦截器 用户自定义拦截器,通常用于监控网络层的数据传输。
CallServerInterceptor 请求拦截器,在前置准备工作完成后,真正发起网络请求,进行IO读写。

这里先大概知道每个拦截器的角色任务,下一篇将会详细分析每个拦截器,以及重要知识点–缓存和连接池。

那么,我们对okhttp执行流程的源码分析,到这里也结束了。

总结

现在通过两篇文章,我们已经掌握了okhttp的基本用法,并且通过阅读源码了解了okhttp总的执行流程——请求的创建、调度、拦截器链处理。接下来的文章,会深入到每个拦截器的具体实现,学习okhttp更多的高级使用技巧。

欢迎关注我的 公 众 号

你想要的系列:网络请求框架OkHttp3全解系列 - (二)OkHttp的工作流程分析相关推荐

  1. python数据挖掘系列教程——PySpider框架应用全解

    全栈工程师开发手册 (作者:栾鹏) python教程全解 python数据挖掘系列教程--PySpider框架应用全解. PySpider介绍 pyspider上手更简单,操作更加简便,因为它增加了 ...

  2. python网络爬虫系列教程——Scrapy框架应用全解

    全栈工程师开发手册 (作者:栾鹏) python教程全解 安装 在cmd中输入 Scrapy的安装依赖wheel.twiste.lxml包.所以先通过pip install wheel安装wheel库 ...

  3. PHP yii 框架源码阅读(二) - 整体执行流程分析

    转载链接:http://tech.ddvip.com/2013-11/1384432766205970.html 一  程序入口 <?php// change the following pat ...

  4. 微服系列之Feign使用HttpClient和OkHttp网络请求框架

    Feign实现了远程调用,底层默认使用的是HttpURLConnection网络请求框架 那Feign支不支持其他的网络请求框架呢,答案那是肯定的,Feign还支持HttpClient和OkHttp, ...

  5. 如何独立开发一个网络请求框架

    (原创出处为本博客:http://www.cnblogs.com/linguanh/) 目录:   前言 准备工作  开发模式 开发原则 线程 高并发 TCP/UDP 本类介绍  开发选择 功能列表 ...

  6. android网络请求框架_2020,最新APP重构:网络请求框架

    在现在的app,网络请求是一个很重要的部分,app中很多部分都有或多或少的网络请求,所以在一个项目重构时,我会选择网络请求框架作为我重构的起点.在这篇文章中我所提出的架构,并不是所谓的 最好 的网络请 ...

  7. 模仿Retrofit封装一个使用更简单的网络请求框架

    本文已授权微信公众号:郭霖  在微信公众号平台原创首发.会用Retrofit了?你也能自己动手写一个! 前言 想封装一套网络请求,不想直接上来就用别人写好的,或者说对项目可以更好的掌控,所以自己模仿着 ...

  8. 一款基于RxJava2+Retrofit2实现简单易用的网络请求框架

    本库是一款基于RxJava2+Retrofit2实现简单易用的网络请求框架,结合android平台特性的网络封装库,采用api链式调用一点到底,集成cookie管理,多种缓存模式,极简https配置, ...

  9. java http 异步请求框架_GitHub - huangdali/MyHttpUtils: 一个非常好用的异步网络请求框架...

    轻量级网络请求框架MyHttputils 一.前言 本版代码大换血,使用了策略模式和构造模式来组织代码,增加了更加人性化的请求构造,代码质量提高.效率显著提升.(但是使用风格基本没变哦) 2.0.2版 ...

最新文章

  1. 把宝可梦搬到终端后,摸鱼也不会被老板发现了,收集对战玩法一应俱全|开源...
  2. 血栓清道夫机器人_血栓“清道夫”找到了!洋葱排最后,排在第一很多人并不知道...
  3. jvm的发展历程:classic、exact、hotspot、BEA的JRockit、IBM的J9、 KVM和CDC/CLDC Hotspot、Azul VM、Liquid VM
  4. 添加vlan后无法上网_KTV多SSID绑定VLAN实用案例,值得一看的干货
  5. HH SaaS电商系统的支付模块设计
  6. C语言可变参数只会用算啥本事?看我来抽丝剥茧干翻它!
  7. 双语站,根据访客自动跳转js
  8. 微服务下的应用架构设计(COLA架构)
  9. Python计算绘图——曲线拟合问题(转)
  10. 什么叫单模光纤_单模光纤是什么?单模光纤有哪些分类?
  11. Python笔记_39_前端_HTML
  12. 小刘的http状态码整理
  13. 3315 时空跳跃者的魔法(一个超级恶心的题目)
  14. 虚拟机快照、迁移、删除
  15. CF1400:1490E、448B、1462FD、650A、1380B、1451C
  16. 健身中心管理_操作简单
  17. Xinlix原语OSERDESE2的使用和仿真
  18. Android App开发基础
  19. 以太坊数据结构MPT 1
  20. gradient_accumulation_steps --梯度累加理解

热门文章

  1. 【爬虫】案例(爬取豆瓣top250)[完整+详细]
  2. crontab的定时操作
  3. 渗透测试-木马免杀的几种方式
  4. python常用小技巧(一)——百度图片批量爬取
  5. Unity3d游戏安装包 极限减少之 四分图、二分图 (NGUI向)
  6. JavaScript点击事件——美女合集
  7. python socket recvfrom_Python:socket.recvfrom()不返回任何地址
  8. 取消Pycharm中sql语句的高亮背景色
  9. 脚本手动执行成功,加入定时任务无法执行
  10. 不用花一分线,松哥手把手教你上线个人博客