当涉及到Android应用程序中的网络请求处理时,OkHttp是一个非常强大和流行的工具。其中一个关键的功能是拦截器(Interceptors),它们允许您在请求和响应传输到服务器和应用程序之间执行各种操作。在本文中,我们将深入研究OkHttp拦截器,了解其工作原理以及如何使用它们来优化您的Android应用程序。
什么是OkHttp拦截器
OkHttp拦截器是一种机制,允许您在网络请求和响应的传输过程中执行自定义操作。它们通常用于记录请求日志、修改请求头、缓存响应或进行身份验证等操作。拦截器可以按照添加它们的顺序依次执行,从而形成一个拦截器链。
拦截器链
拦截器链是一个由多个拦截器组成的链条,每个拦截器在请求和响应的传输过程中都有机会进行操作。这些拦截器按照它们添加的顺序执行,因此顺序很重要。以下是一个拦截器链的示意图:
1 2 3
| Request 1 -> Interceptor 1 -> Interceptor 2 -> ... -> Interceptor N -> Server <- <- ... <- <- Response 1 <- Interceptor 1 <- Interceptor 2 <- ... <- Interceptor N <- Server
|
OkHttp中拦截器的工作原理
OkHttp的核心组件是Interceptor
接口和RealCall
类。Interceptor
接口定义了intercept()
方法,它接收一个Chain
对象作为参数,该对象用于执行拦截器链上的操作。RealCall
类用于实际执行网络请求并管理拦截器链的执行。
创建OkHttpClient
首先,您需要创建一个OkHttpClient
实例,该实例用于发起网络请求,并配置拦截器链。
1 2 3
| OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new CustomInterceptor()) .build();
|
发起网络请求
当您调用client.newCall(request)
来创建一个新的网络请求时,OkHttp会创建一个RealCall
对象,该对象代表了实际的网络请求。接下来,RealCall
会执行拦截器链上的操作。
1 2 3 4 5 6
| Request request = new Request.Builder() .url("https://example.com/api") .build();
Call call = client.newCall(request); Response response = call.execute();
|
拦截器链执行
拦截器链的执行是在RealCall
类中完成的,它遍历拦截器列表并按照添加顺序依次执行。以下是相关源码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public Response getResponseWithInterceptorChain() throws IOException { 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);
return chain.proceed(originalRequest); }
|
Interceptor.Chain的实现
RealInterceptorChain
类实现了Interceptor.Chain
接口,它包含了当前请求的信息,并负责执行拦截器链上的操作。在proceed()
方法中,它依次调用拦截器的intercept()
方法,将请求传递给下一个拦截器,并最终返回响应。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public Response proceed(Request request) throws IOException { if (index >= interceptors.size()) throw new AssertionError(); calls++; if (chain == null) throw new IllegalStateException("Check failed."); if (eventListener != null) { eventListener.callStart(this); }
Interceptor interceptor = interceptors.get(index++);
Response response = interceptor.intercept(this);
if (eventListener != null) { eventListener.callEnd(this); }
return response; }
|
编写自定义拦截器
要编写自定义拦截器,首先需要实现Interceptor
接口,并实现intercept()
方法。这个方法接收一个Chain
对象作为参数,允许您访问和操作请求和响应。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class CustomInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); Request modifiedRequest = originalRequest.newBuilder() .addHeader("Authorization", "Bearer YourAccessToken") .build(); Response response = chain.proceed(modifiedRequest); return response; } }
|
实际应用示例
以下是一些实际运用示例,展示了如何使用OkHttp拦截器来实现不同的功能
日志记录
这个拦截器用于记录请求和响应的详细信息,有助于调试和排查问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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; } }
|
身份验证
这个拦截器用于在每个请求中添加身份验证标头,以确保请求是经过身份验证的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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(); Request authenticatedRequest = originalRequest.newBuilder() .header("Authorization", "Bearer " + authToken) .build(); return chain.proceed(authenticatedRequest); } }
|
缓存
这个拦截器用于实现响应缓存,以减少对服务器的请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class CacheInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); return response; } }
|
请求重试
这个拦截器用于处理请求失败时的重试逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 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; } }
throw lastException; } }
|
自定义响应处理
这个拦截器用于在接收到响应后执行自定义的响应处理逻辑。
1 2 3 4 5 6 7 8 9 10 11
| public class ResponseProcessingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); return response; } }
|
错误处理
这个拦截器用于处理一些常见的错误情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class ErrorHandlingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); try { Response response = chain.proceed(request); if (!response.isSuccessful()) { throw new MyHttpException(response.code(), response.message()); } return response; } catch (IOException e) { throw new MyNetworkException(e.getMessage(), e); } } }
|
重定向请求
这个拦截器用于自定义重定向行为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class RedirectInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); if (response.isRedirect()) { String newUrl = response.header("Location"); if (newUrl != null) { Request newRequest = request.newBuilder() .url(newUrl) .build(); response = chain.proceed(newRequest); } } return response; } }
|
结论
OkHttp拦截器是Android应用程序中处理网络请求的有力工具。通过创建自定义拦截器,您可以在请求和响应的传输过程中执行各种操作,以优化您的应用程序。无论是日志记录、身份验证、缓存还是其他操作,拦截器都可以帮助您更好地控制和定制网络请求流程。
推荐
android_startup: 提供一种在应用启动时能够更加简单、高效的方式来初始化组件,优化启动速度。不仅支持Jetpack App Startup的全部功能,还提供额外的同步与异步等待、线程控制与多进程支持等功能。
AwesomeGithub: 基于Github的客户端,纯练习项目,支持组件化开发,支持账户密码与认证登陆。使用Kotlin语言进行开发,项目架构是基于JetPack\&DataBinding的MVVM;项目中使用了Arouter、Retrofit、Coroutine、Glide、Dagger与Hilt等流行开源技术。
flutter_github: 基于Flutter的跨平台版本Github客户端,与AwesomeGithub相对应。
android-api-analysis: 结合详细的Demo来全面解析Android相关的知识点, 帮助读者能够更快的掌握与理解所阐述的要点。
daily_algorithm: 每日一算法,由浅入深,欢迎加入一起共勉。