这篇文章简要介绍OkHttp的请求和响应过程。文章基于OkHttp3.14.3版本java
OkHttp做为当下Java系编程的网络请求库,其热门程度自没必要说了。网上有关OkHttp的使用、封装和源码分析的文章和代码也早已经是百家齐放、甚至能够说是烂大街了。然而尽管如此,笔者仍是但愿可以将对OkHttp的学习和研究记录下来造成本身的内容,方便之后查看,因而开始写吧,好记性不如烂笔头。git
那就从最简单的开始。这篇文章打算简要描述一下OkHttp中大体的请求响应过程。github
首先看看简单的同步GET请求和异步GET请求:web
public static void getSync() { // Step 1. 建立一个HttpClient实例用于建立请求任务 OkHttpClient httpClient = new OkHttpClient(); // Step 2. 构建一个Request用于封装请求地址、请求类型、参数等信息 Request request = new Request.Builder().get() .url("https://www.baidu.com") .build(); // Step 3. 建立一个新的请求任务Call Call call = httpClient.newCall(request); try { // Step 4. 发起请求 Response response = call.execute(); // Step 5. 读取、处理请求结果 ResponseBody responseBody = response.body(); if (responseBody != null) { System.out.println(responseBody.string()); } } catch (IOException e) { e.printStackTrace(); } }
public void getAsync() { // Step 1. 建立一个HttpClient实例用于建立请求任务 OkHttpClient httpClient = new OkHttpClient(); // Step 2. 构建一个Request用于封装请求地址、请求类型、参数等信息 Request request = new Request.Builder().get() .url("https://www.baidu.com") .build(); // Step 3. 建立一个新的请求任务Call Call call = httpClient.newCall(request); // Step 4. 发起请求 call.enqueue(new Callback() { @Override public void onFailure(final Call call, final IOException e) { e.printStackTrace(); } @Override public void onResponse(final Call call, final Response response) throws IOException { // Step 5. 读取、处理请求结果 ResponseBody responseBody = response.body(); if (responseBody != null) { System.out.println(responseBody.string()); } } }); }
能够看到,无论是同步仍是异步请求,都须要通过Step1~Step3三个步骤构建一个请求任务,并经过调用call.execute()/call.enqueue(callback)来执行同步/异步请求。那接下来就看看这两个方法的执行过程吧。编程
首先看看call.execute():缓存
点击查看Call类,发现Call是一个接口,尝试跳转到call.execute()方法的具体实现(ps: AS快捷键Ctrl+Alt+B实现快速跳转到方法的具体实现),来到Call接口的惟一实现类RealCall类,RealCall.execute()具体实现以下:服务器
@Override public Response execute() throws IOException { // Step 1. synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } // Step 2. transmitter.timeoutEnter(); transmitter.callStart(); try { // Step 3. client.dispatcher().executed(this); // Step 4. return getResponseWithInterceptorChain(); } finally { // Step 5. client.dispatcher().finished(this); } }
/** 正在运行的同步请求任务,包括还没有结束就已经取消同步请求. */ private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
通过以上这几个步骤,一次同步GET请求就算是结束了。能够发现,RealCall.getResponseWithInterceptorChain()方法负责进行具体的HTTP请求,这里暂时不跟进去,先来看看异步的GET请求:websocket
Ctrl+Alt+B
快速跳转到call.enqueue(callback)的具体实现RealCall.enqueue(callback):cookie
@Override public void enqueue(Callback responseCallback) { // Step 1. synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } // Step 2. transmitter.callStart(); // Step 3. client.dispatcher().enqueue(new AsyncCall(responseCallback)); }
@Override protected void execute() { boolean signalledCallback = false; // Step 3.1 开始计算请求超时时间 transmitter.timeoutEnter(); try { // Step 3.2 发起请求并获取请求结果 Response response = getResponseWithInterceptorChain(); signalledCallback = true; // Step 3.3 请求成功,将结果经过回调接口返回给上层 responseCallback.onResponse(RealCall.this, response); } catch (IOException e) { if (signalledCallback) { // Do not signal the callback twice! Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e); } else { // 请求失败 responseCallback.onFailure(RealCall.this, e); } } finally { // Step 4.结束本次请求任务,并从队列中移除 client.dispatcher().finished(this); } } }
而查阅execute的实现也验证了这个断定是正确的,至于什么时候,从哪儿,会执行到这个execute方法,先留个小坑吧后续再填~。同时,对比RealCall.execute()方法(同步请求)和AsyncCall.execute()方法(异步请求)发现,无论是同步仍是异步请求,最后都会经过调用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) { // 若是本次请求任务不是websocket请求,则添加网络拦截器,该拦截器也须要用户自定义 interceptors.addAll(client.networkInterceptors()); } // 添加最后一个拦截器,该拦截器负责执行最终的网络请求并返回结果 interceptors.add(new CallServerInterceptor(forWebSocket)); // 构建一个拦截器链chain对象 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); } } }
能够看到,这个方法最终是经过chain.proceed(originalRequest);实现请求和返回结果,到这里,OkHttp的请求过程就结束了。所以,一个OkHttp的请求过程大体以下:
先到这里吧。原本想着一篇写完的但太长了彷佛本身都不想看,仍是一步步来吧。下一篇开始着重分析以上OkHttp请求过程当中接触到的各个关键的类。
欢迎关注公众号:
![]()
文章首发在我的博客 https://www.nullobject.cn,公众号 NullObject同步更新。