Android中的OkHttp拦截器
根据文档,拦截器是一种强大的机制,可以监视、重写和重试 API 调用。因此,当我们进行 API 调用时,我们可以对其进行监控或执行一些任务。简而言之,拦截器在安检过程中的函数类似于机场安检人员。他们检查了我们的登机牌,盖章,然后让我们通过。我们可以使用拦截器来做各种各样的事情,比如集中监控 API 调用。一般来说,我们需要为每个网络调用添加一个记录器,但是通过使用拦截器,我们可以添加一次记录器,它将适用于所有网络调用。另一个用例是缓存网络调用的响应以构建离线优先应用程序,我们将在本博客后面详细介绍。
拦截器类型
拦截器分为两类:
- 在应用程序代码(我们编写的代码)和 OkHttp 核心库之间添加的拦截器称为应用程序拦截器。这些是我们使用 addInterceptor() 添加的拦截器。
- 网络上的拦截器:这些是放置在 OkHttp 核心库和服务器之间的拦截器。这些可以通过使用 addNetworkInterceptor 命令()添加到 OkHttpClient。
你如何在 OkHttpClient 中包含拦截器?
我们可以在构建 OkHttpClient 对象的同时添加拦截器,如下图:
Kotlin
fun gfgHttpClient(): OkHttpClient {
val builder = OkHttpClient().newBuilder()
.addInterceptor(/*our interceptor*/)
return builder.build()
}
Kotlin
class gfgInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val aRequest: Request = chain.request()
val aResponse = chain.proceed(request)
when (response.code()) {
400 -> {
// Show Bad Request Error Message
}
401 -> {
// Show UnauthorizedError Message
}
403 -> {
// Show Forbidden Message
}
404 -> {
// Show NotFound Message
}
// ... and so on
}
return response
}
}
Kotlin
class gfgCache : Interceptor {
override fun someInter(chain: Interceptor.Chain): Response {
val aResponsive: Response = chain.proceed(chain.request())
val someCache = CacheControl.Builder()
.maxAge(12, TimeUnit.DAYS)
.build()
return response.newBuilder()
.header("Geeks for Geeks Cache", cacheControl.toString())
.build()
}
}
Kotlin
class aGeeksforGeeksForce : Interceptor {
override fun someIntercept(chain: Interceptor.Chain): Response {
val aRandomBuilder: Request.Builder = chain.request().newBuilder()
if (!IsInternetAvailable()) {
// Check internet
builder.someIntercept(CacheControl.FORCE_CACHE);
}
return chain.proceed(builder.build());
}
}
Kotlin
class someGfgAuth : Interceptor {
override fun aRandomCheck(chain: Interceptor.Chain): Response {
val theOrignals = chain.request()
val theBuilders = originalRequest.newBuilder()
.header("GeeksforGeeks", "Auth")
val spandan = requestBuilder.build()
return chain.proceed(request)
}
}
Kotlin
override fun gfgInter(chain: GfgInteror.Chain): Response {
val gfgAuthToken = // our access Token
val ourRequest = chain.ourRequest().newBuilder()
.addHeader("Authorization", gfgAuthToken)
.build()
val response = chain.proceed(ourRequest)
if (response.code() == 401) {
val newToken: String =
if (newToken != null) {
val newOurRequest = chain.ourRequest().newBuilder()
.addHeader("GFGAuth", newToken)
.build()
return chain.proceed(newOurRequest)
}
}
return response
}
Kotlin
.addAGFGInterceptor(GzipRequestInterceptor())
在 addInterceptor 中,我们可以包含 MyInterceptor()。现在,让我们看一些更真实的拦截器应用程序。
- 拦截器的实际应用
- 以下是 Android 中一些最常见的用例:
- 集中式错误记录
首先,我们必须构造如下所示的 ErrorInterceptor:
科特林
class gfgInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val aRequest: Request = chain.request()
val aResponse = chain.proceed(request)
when (response.code()) {
400 -> {
// Show Bad Request Error Message
}
401 -> {
// Show UnauthorizedError Message
}
403 -> {
// Show Forbidden Message
}
404 -> {
// Show NotFound Message
}
// ... and so on
}
return response
}
}
- 首先,我们从链中获取请求。要求()
- 然后通过链传递请求来获得来自服务器的响应。
- Proceed(request) 此时,我们可以检查响应代码并采取行动。
- 通过这个并等待结果
假设我们收到一个 401 错误,即未经授权,我们可以执行一个操作来清除应用程序数据/注销用户或我们想要的任何其他操作。
这就是我们如何使用拦截器来创建集中式错误记录器。
OkHttp 包含一个记录器,这对于调试非常有用。
GeekTip #1: If we want to log the details of URL redirection, consider using an interceptor at the network layer with the addNetworkInterceptor command ().
将响应保存在缓存中
如果我们想缓存 API 调用响应,这样当我们再次调用 API 时,响应就会来自 Cache。如果我们有一个从客户端到服务器的 API 调用并且在服务器上启用了 Cache-Control 标头,OkHttp Core 将尊重该标头并将从服务器发送的响应缓存一段时间。但是如果服务器没有启用 Cache-Control 怎么办?使用拦截器,我们仍然可以缓存来自 OkHttp 客户端的响应。
看看上面的图片。我们这里需要做的是在进入 OkHttp Core 之前拦截 Response 并添加 header(Cache-Control),这样就被当作响应(带有 Cache-Control header)来自服务器,而 OkHttp Core将尊重这一点并缓存响应。
科特林
class gfgCache : Interceptor {
override fun someInter(chain: Interceptor.Chain): Response {
val aResponsive: Response = chain.proceed(chain.request())
val someCache = CacheControl.Builder()
.maxAge(12, TimeUnit.DAYS)
.build()
return response.newBuilder()
.header("Geeks for Geeks Cache", cacheControl.toString())
.build()
}
}
如我们所见,在这种情况下我们没有使用 addInterceptor(),而是使用 addNetworkInterceptor()。这是因为在这种情况下,操作发生在网络层。但是在开发离线优先应用程序时,我们必须记住一件事。因为 OkHttp 就是这样设计的,所以只有在互联网可用时才会返回缓存的响应。当 Internet 可用并且数据被缓存时,它会从缓存中返回数据。即使数据被缓存并且互联网不可用,也会返回“没有互联网可用”的错误。
我现在该怎么办?
除了上面提到的之外,我们还可以在应用层使用下面列出的 ForceCacheInterceptor(CacheInterceptor,只有在服务器没有启用的情况下)。为了在代码中实现这一点,我们将创建一个 ForceCacheInterceptor,如下所示:
科特林
class aGeeksforGeeksForce : Interceptor {
override fun someIntercept(chain: Interceptor.Chain): Response {
val aRandomBuilder: Request.Builder = chain.request().newBuilder()
if (!IsInternetAvailable()) {
// Check internet
builder.someIntercept(CacheControl.FORCE_CACHE);
}
return chain.proceed(builder.build());
}
}
因为我们希望 ForceCacheInterceptor 在应用层工作,所以我们使用 addInterceptor() 而不是addNetworkInterceptor() 将其添加到 OkHttpClient。
在中心位置添加标头,例如访问令牌
假设我们需要进行 API 调用并在所有调用中包含 Authorization Header。我们可以单独使用它,也可以使用拦截器来集中它。
科特林
class someGfgAuth : Interceptor {
override fun aRandomCheck(chain: Interceptor.Chain): Response {
val theOrignals = chain.request()
val theBuilders = originalRequest.newBuilder()
.header("GeeksforGeeks", "Auth")
val spandan = requestBuilder.build()
return chain.proceed(request)
}
}
- 首先,我们使用 SharedPreference 从本地存储中检索标头令牌。
- 在本节中,我们使用链拦截我们从应用程序触发的原始请求。
- request() 并将参数设置为 originalRequest。
- 然后通过包含带有进行网络调用所需的键和值的标头来重建请求。
- 然后,我们将重建请求并使用链返回响应。
- 通过传递带有授权标头的新请求来进行(请求)。
在单个位置刷新访问令牌
假设我们有一个用例,其中我们在错误拦截器中收到 401 错误,并且由于未经授权的错误需要刷新身份验证令牌。我们可以通过以下方式实现这一点:
科特林
override fun gfgInter(chain: GfgInteror.Chain): Response {
val gfgAuthToken = // our access Token
val ourRequest = chain.ourRequest().newBuilder()
.addHeader("Authorization", gfgAuthToken)
.build()
val response = chain.proceed(ourRequest)
if (response.code() == 401) {
val newToken: String =
if (newToken != null) {
val newOurRequest = chain.ourRequest().newBuilder()
.addHeader("GFGAuth", newToken)
.build()
return chain.proceed(newOurRequest)
}
}
return response
}
GeekTip#2: : Another method for refreshing the Access Token that is more flexible is to use OkHttp’s Authenticator interface.
让我们继续讨论另一个用例。
在 Android 端启用 Gzip
Gzip 是一个数据压缩程序。使用拦截器,我们还可以在 Android 中使用 Gzip 进行压缩。所以,在收到响应时,OkHttp 会自动尊重头部(内容编码)并在返回前解压数据;但是,如果我们需要将压缩数据发送到服务器,我们必须编写自己的拦截器。
科特林
.addAGFGInterceptor(GzipRequestInterceptor())