OkHttp攔截器在Android網(wǎng)絡(luò)中的使用和工作原理
什么是OkHttp攔截器
OkHttp攔截器是一種機(jī)制,允許您在網(wǎng)絡(luò)請(qǐng)求和響應(yīng)的傳輸過(guò)程中執(zhí)行自定義操作。它們通常用于記錄請(qǐng)求日志、修改請(qǐng)求頭、緩存響應(yīng)或進(jìn)行身份驗(yàn)證等操作。攔截器可以按照添加它們的順序依次執(zhí)行,從而形成一個(gè)攔截器鏈。
攔截器鏈
攔截器鏈?zhǔn)且粋€(gè)由多個(gè)攔截器組成的鏈條,每個(gè)攔截器在請(qǐng)求和響應(yīng)的傳輸過(guò)程中都有機(jī)會(huì)進(jìn)行操作。這些攔截器按照它們添加的順序執(zhí)行,因此順序很重要。以下是一個(gè)攔截器鏈的示意圖:
Request 1 -> Interceptor 1 -> Interceptor 2 -> ... -> Interceptor N -> Server <- <- ... <- <- Response 1 <- Interceptor 1 <- Interceptor 2 <- ... <- Interceptor N <- Server
OkHttp中攔截器的工作原理
OkHttp的核心組件是Interceptor
接口和RealCall
類。Interceptor
接口定義了intercept()
方法,它接收一個(gè)Chain
對(duì)象作為參數(shù),該對(duì)象用于執(zhí)行攔截器鏈上的操作。RealCall
類用于實(shí)際執(zhí)行網(wǎng)絡(luò)請(qǐng)求并管理攔截器鏈的執(zhí)行。
創(chuàng)建OkHttpClient
首先,您需要?jiǎng)?chuàng)建一個(gè)OkHttpClient
實(shí)例,該實(shí)例用于發(fā)起網(wǎng)絡(luò)請(qǐng)求,并配置攔截器鏈。
OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new CustomInterceptor()) .build();
發(fā)起網(wǎng)絡(luò)請(qǐng)求
當(dāng)您調(diào)用client.newCall(request)
來(lái)創(chuàng)建一個(gè)新的網(wǎng)絡(luò)請(qǐng)求時(shí),OkHttp會(huì)創(chuàng)建一個(gè)RealCall
對(duì)象,該對(duì)象代表了實(shí)際的網(wǎng)絡(luò)請(qǐng)求。接下來(lái),RealCall
會(huì)執(zhí)行攔截器鏈上的操作。
Request request = new Request.Builder() .url("https://example.com/api") .build(); Call call = client.newCall(request); Response response = call.execute();
攔截器鏈執(zhí)行
攔截器鏈的執(zhí)行是在RealCall
類中完成的,它遍歷攔截器列表并按照添加順序依次執(zhí)行。以下是相關(guān)源碼示例:
public Response getResponseWithInterceptorChain() throws IOException { // 創(chuàng)建一個(gè)初始的Interceptor.Chain 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)); interceptors.add(new CallServerInterceptor(false)); Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, 0, originalRequest, this, callStackTrace); // 依次執(zhí)行攔截器 return chain.proceed(originalRequest); }
Interceptor.Chain的實(shí)現(xiàn)
RealInterceptorChain
類實(shí)現(xiàn)了Interceptor.Chain
接口,它包含了當(dāng)前請(qǐng)求的信息,并負(fù)責(zé)執(zhí)行攔截器鏈上的操作。在proceed()
方法中,它依次調(diào)用攔截器的intercept()
方法,將請(qǐng)求傳遞給下一個(gè)攔截器,并最終返回響應(yīng)。
public Response proceed(Request request) throws IOException { // 執(zhí)行下一個(gè)攔截器或者發(fā)起網(wǎng)絡(luò)請(qǐng)求 if (index >= interceptors.size()) throw new AssertionError(); calls++; if (chain == null) throw new IllegalStateException("Check failed."); if (eventListener != null) { eventListener.callStart(this); } // 獲取當(dāng)前攔截器 Interceptor interceptor = interceptors.get(index++); // 調(diào)用攔截器的intercept方法,將請(qǐng)求傳遞給下一個(gè)攔截器或者執(zhí)行網(wǎng)絡(luò)請(qǐng)求 Response response = interceptor.intercept(this); if (eventListener != null) { eventListener.callEnd(this); } return response; }
編寫(xiě)自定義攔截器
要編寫(xiě)自定義攔截器,首先需要實(shí)現(xiàn)Interceptor
接口,并實(shí)現(xiàn)intercept()
方法。這個(gè)方法接收一個(gè)Chain
對(duì)象作為參數(shù),允許您訪問(wèn)和操作請(qǐng)求和響應(yīng)。
public class CustomInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { // 在請(qǐng)求前執(zhí)行的代碼 Request originalRequest = chain.request(); // 可以修改請(qǐng)求 Request modifiedRequest = originalRequest.newBuilder() .addHeader("Authorization", "Bearer YourAccessToken") .build(); // 執(zhí)行請(qǐng)求 Response response = chain.proceed(modifiedRequest); // 在響應(yīng)后執(zhí)行的代碼 // 可以修改響應(yīng) return response; } }
實(shí)際應(yīng)用示例
以下是一些實(shí)際運(yùn)用示例,展示了如何使用OkHttp攔截器來(lái)實(shí)現(xiàn)不同的功能
日志記錄
這個(gè)攔截器用于記錄請(qǐng)求和響應(yīng)的詳細(xì)信息,有助于調(diào)試和排查問(wèn)題。
public class LoggingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); long startTime = System.nanoTime(); Log.d("OkHttp", String.format("Sending request %s on %s%n%s", request.url(), chain.connection(), request.headers())); Response response = chain.proceed(request); long endTime = System.nanoTime(); Log.d("OkHttp", String.format("Received response for %s in %.1fms%n%s", response.request().url(), (endTime - startTime) / 1e6d, response.headers())); return response; } }
身份驗(yàn)證
這個(gè)攔截器用于在每個(gè)請(qǐng)求中添加身份驗(yàn)證標(biāo)頭,以確保請(qǐng)求是經(jīng)過(guò)身份驗(yàn)證的。
public class AuthInterceptor implements Interceptor { private final String authToken; public AuthInterceptor(String authToken) { this.authToken = authToken; } @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); // 添加身份驗(yàn)證標(biāo)頭 Request authenticatedRequest = originalRequest.newBuilder() .header("Authorization", "Bearer " + authToken) .build(); return chain.proceed(authenticatedRequest); } }
緩存
這個(gè)攔截器用于實(shí)現(xiàn)響應(yīng)緩存,以減少對(duì)服務(wù)器的請(qǐng)求。
public class CacheInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // 在這里檢查是否有緩存可用,如果有,返回緩存的響應(yīng) Response response = chain.proceed(request); // 在這里將響應(yīng)緩存起來(lái) return response; } }
請(qǐng)求重試
這個(gè)攔截器用于處理請(qǐng)求失敗時(shí)的重試邏輯。
public class RetryInterceptor implements Interceptor { private final int maxRetryCount; public RetryInterceptor(int maxRetryCount) { this.maxRetryCount = maxRetryCount; } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = null; IOException lastException = null; for (int retryCount = 0; retryCount < maxRetryCount; retryCount++) { try { response = chain.proceed(request); if (response.isSuccessful()) { return response; } } catch (IOException e) { lastException = e; } } // 如果達(dá)到最大重試次數(shù)仍然失敗,拋出異常 throw lastException; } }
自定義響應(yīng)處理
這個(gè)攔截器用于在接收到響應(yīng)后執(zhí)行自定義的響應(yīng)處理邏輯。
public class ResponseProcessingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); // 在這里對(duì)響應(yīng)進(jìn)行自定義處理 return response; } }
錯(cuò)誤處理
這個(gè)攔截器用于處理一些常見(jiàn)的錯(cuò)誤情況
public class ErrorHandlingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); try { Response response = chain.proceed(request); // 檢查響應(yīng)是否成功 if (!response.isSuccessful()) { // 在這里處理錯(cuò)誤,可以拋出自定義異常 throw new MyHttpException(response.code(), response.message()); } return response; } catch (IOException e) { // 在這里處理網(wǎng)絡(luò)連接錯(cuò)誤 throw new MyNetworkException(e.getMessage(), e); } } }
重定向請(qǐng)求
這個(gè)攔截器用于自定義重定向行為
public class RedirectInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); // 檢查是否是重定向響應(yīng) if (response.isRedirect()) { String newUrl = response.header("Location"); if (newUrl != null) { // 構(gòu)建新的請(qǐng)求并繼續(xù) Request newRequest = request.newBuilder() .url(newUrl) .build(); response = chain.proceed(newRequest); } } return response; } }
結(jié)論
OkHttp攔截器是Android應(yīng)用程序中處理網(wǎng)絡(luò)請(qǐng)求的有力工具。通過(guò)創(chuàng)建自定義攔截器,您可以在請(qǐng)求和響應(yīng)的傳輸過(guò)程中執(zhí)行各種操作,以優(yōu)化您的應(yīng)用程序。無(wú)論是日志記錄、身份驗(yàn)證、緩存還是其他操作,攔截器都可以幫助您更好地控制和定制網(wǎng)絡(luò)請(qǐng)求流程。
以上就是OkHttp攔截器在Android網(wǎng)絡(luò)中的使用和工作原理的詳細(xì)內(nèi)容,更多關(guān)于OkHttp攔截器在Android中的使用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Android入門之使用OKHttp多線程下載文件
- Android 使用 okhttp3和retrofit2 進(jìn)行單文件和多文件上傳
- Android基于OkHttp實(shí)現(xiàn)文件上傳功能
- Android使用OKhttp3實(shí)現(xiàn)登錄注冊(cè)功能+springboot搭建后端的詳細(xì)過(guò)程
- Android的簡(jiǎn)單前后端交互(okHttp+springboot+mysql)
- Android Okhttp斷點(diǎn)續(xù)傳面試深入解析
- Android使用OkHttp發(fā)送post請(qǐng)求
- Android使用OkHttp進(jìn)行網(wǎng)絡(luò)同步異步操作
- Android視頻/音頻緩存框架AndroidVideoCache(Okhttp)詳解
- Android OkHttp實(shí)現(xiàn)全局過(guò)期token自動(dòng)刷新示例
- OkHttp原理分析小結(jié)
相關(guān)文章
完美解決EditText和ScrollView的滾動(dòng)沖突(上)
這篇文章主要為大家詳細(xì)介紹了完美解決EditText和ScrollView滾動(dòng)沖突的方法,感興趣的小伙伴們可以參考一下2016-06-06Cocos2d-x 3.0中集成社交分享ShareSDK的詳細(xì)步驟和常見(jiàn)問(wèn)題解決
這篇文章主要介紹了Cocos2d-x 3.0中集成社交分享ShareSDK的詳細(xì)步驟和常見(jiàn)問(wèn)題的解決方法以及需要注意的問(wèn)題,需要的朋友可以參考下2014-04-04Android實(shí)現(xiàn)果凍滑動(dòng)效果的控件
這篇文章給大家主要介紹了利用Android如何實(shí)現(xiàn)果凍效果滑動(dòng)效果的控件,實(shí)現(xiàn)的效果類似于iOS有阻尼效果的滑動(dòng)控件,一般我們比較親切地稱之為果凍控件,常見(jiàn)的如微信里[我]的那個(gè)面板模塊,即使沒(méi)有再多的選項(xiàng),也不會(huì)很生硬的不允許用戶滑動(dòng)。下面來(lái)一起看看吧。2016-11-11RecyclerVIew實(shí)現(xiàn)懸浮吸頂效果
這篇文章主要為大家詳細(xì)介紹了RecyclerVIew實(shí)現(xiàn)懸浮吸頂效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09Android CardView詳解及使用方法和實(shí)例
這篇文章主要介紹了Android CardView詳解及使用方法和實(shí)例的相關(guān)資料,這里附有實(shí)例代碼及實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-12-12Android?獲取IP和UA實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了Android?獲取IP和UA實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Android?進(jìn)入Activity時(shí)如何禁止彈出軟鍵盤輸入法
這篇文章主要介紹了Android?進(jìn)入Activity時(shí)如何禁止彈出軟鍵盤輸入法,文章圍繞主題展開(kāi)具體內(nèi)容,需要的小伙伴可以參考一下2022-05-05Android自定義控件實(shí)現(xiàn)球賽比分條效果
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)球賽比分條效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12Flutter 枚舉值enum和int互相轉(zhuǎn)化總結(jié)
這篇文章主要為大家介紹了Flutter 枚舉值enum和int互相轉(zhuǎn)化總結(jié)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02