這篇文章簡要介紹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同步更新。