Interceptor — 什么是拦截器,OkHttp 和 Alamofire 的拦截器类型

作者: IT Sectr 发布日期: 2026-03-08 阅读时间: 8 分钟

Interceptor — OkHttp 和 Alamofire 的组件,用于拦截 HTTP 请求和响应以进行日志记录、身份验证、缓存和重试。根据 Square(2026)的数据,正确配置的拦截器可将网络问题的调试时间缩短 40%,并标准化错误处理。Application Interceptor 每个请求触发一次,Network Interceptor — 每次重定向触发一次。

要点

  • Interceptor — OkHttp 和 Alamofire 中用于横切任务的 HTTP 请求和响应拦截器。
  • Application Interceptor 在应用程序和 OkHttp 之间在请求之前和之后执行一次。
  • Network Interceptor 在 OkHttp 内部的每次重定向和重试时触发。
  • RequestInterceptor 在 Alamofire 中结合了请求适配和重试。
  • Chain.proceed() — OkHttp 的关键方法,通过拦截器链传递请求。

什么是 Interceptor?

Interceptor — 注入到 HTTP 客户端中的软件组件,用于在发送到服务器之前拦截和修改请求,以及在传递到应用程序之前拦截和修改响应。在移动开发中,拦截器解决横切任务:自动添加身份验证令牌、带时间测量的流量日志记录、临时网络错误时的重试、即时压缩和解密数据。Interceptor 架构基于 Chain of Responsibility(责任链)模式 — 每个拦截器可以修改请求、执行请求或通过返回自定义响应来中断链。

拦截器链如何工作

在 OkHttp 中,拦截器形成一条链。每个 Interceptor 接收一个包含原始请求的 Chain 对象,并调用 chain.proceed(request) 将控制权传递给下一个拦截器。收到响应后,拦截器可以分析 Response、修改它、在出错时重试请求或返回自定义响应以进行缓存。在 OkHttpClient.Builder 中添加拦截器的顺序决定了它们的执行顺序:第一个添加的在发送时第一个执行,在接收时最后一个执行。

OkHttp 中的 Interceptor:Application 和 Network

OkHttp 将拦截器分为两种类型。Application Interceptor(addInterceptor)在应用程序代码和 OkHttp 之间执行:一次 chain.proceed() 调用 — 一次对服务器的请求,无论重定向如何。Network Interceptor(addNetworkInterceptor)在 OkHttp 内部在形成标头和连接后执行 — 在每次重定向、重试或身份验证时触发。这种区别对于为特定任务选择正确的拦截器类型至关重要。

kotlin
class LoggingInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        Log.d("HTTP", "${request.method} ${request.url}")

        val startTime = System.currentTimeMillis()
        val response = chain.proceed(request)
        val duration = System.currentTimeMillis() - startTime

        Log.d("HTTP", "${response.code} 在 ${duration}ms 内")
        return response
    }
}

val client = OkHttpClient.Builder()
    .addInterceptor(LoggingInterceptor())
    .addNetworkInterceptor(CacheInterceptor())
    .build()

LoggingInterceptor — Application Interceptor,记录方法、URL、响应代码和执行时间。通过 addInterceptor() 添加保证每个用户请求一个日志,而不会在重定向时重复。CacheInterceptor 作为 Network Interceptor 添加,以考虑服务器的 Cache-Control 标头,这些标头仅在 OkHttp 内部在形成 HTTP 请求后可见。

类型之间的实际区别

当应用程序发出请求时,服务器可能会以 302 或 301 重定向响应。Application Interceptor 只能看到所有重定向后的最终响应 — 它不知道进行了多少中间请求。Network Interceptor 可以看到每个请求和响应,包括中间请求和响应。根据 Square(2026)的数据,Network Interceptor 还可以看到在连接级别压缩(gzip)的数据,而 Application Interceptor 接收已解压缩的响应。要计算实际网络调用次数,请使用 Network Interceptor。

Alamofire RequestInterceptor

Alamofire 提供 RequestInterceptor 协议,该协议结合了两个协议:RequestAdapter 用于在发送前修改请求,RequestRetrier 用于在出错时重试。这种分离允许将适配(添加标头、令牌)与重试策略(指数退避、尝试限制、错误类型检查)灵活组合。RequestInterceptor 由同时实现这两个协议的单一结构或类实现。

swift
struct AuthInterceptor: RequestInterceptor {
    private let tokenProvider: TokenProvider

    func adapt(_ urlRequest: URLRequest,
                using state: Session.RequestAdapterState,
                completion: @escaping (Result<URLRequest, Error>) -> Void) {
        var request = urlRequest
        request.setValue("Bearer \(tokenProvider.token)",
                        forHTTPHeaderField: "Authorization")
        completion(.success(request))
    }

    func retry(_ request: Request,
               for session: Session,
               dueTo error: Error,
               completion: @escaping (RetryResult) -> Void) {
        if error is URLError {
            completion(.retryWithDelay(1))
        } else {
            completion(.doNotRetry)
        }
    }
}

AuthInterceptor 在 Swift 中通过 adapt 添加 Bearer 令牌,并在 URLError(网络丢失、超时)时通过 retry 自动重试请求,延迟 1 秒。适配和重试的分离允许独立测试它们 — 可以为适配编写单元测试而不影响重试逻辑。根据 Alamofire(2026)的数据,RequestInterceptor 是 iOS 项目中集中式身份验证管理的标准方式。

拦截器的使用场景

日志记录 — 最常见的场景。Interceptor 记录 URL、方法、标头、请求和响应正文、执行时间。在调试构建中,这取代了 Charles Proxy 和 Wireshark,在发布版本中 — 帮助带有请求上下文的错误报告。对于 OkHttp,使用来自 logging-interceptor 库的 HttpLoggingInterceptor,具有 NONE、BASIC、HEADERS 和 BODY 级别。BODY 级别记录完整的请求和响应正文 — 仅用于调试。

身份验证和刷新令牌

当访问令牌过期时,Interceptor 拦截 401 响应,调用刷新令牌 API,并使用新令牌重试原始请求。在 OkHttp 中,这是通过 Authenticator 或带有 response.code 检查的自定义 Interceptor 实现的。Authenticator 只能访问响应标头,Interceptor — 可以访问完整正文。在 Alamofire 中 — 通过 RequestRetrier,在令牌刷新后返回 .retry。根据 OWASP(2026)的数据,通过 Interceptor 自动刷新令牌可降低凭据泄露的风险。

添加通用标头

Content-Type、Accept-Language、User-Agent、Device-ID — 每个请求所需的标头。Interceptor 集中添加它们,而无需在每个 API 方法中重复。User-Agent 在应用程序启动时创建一次:“AppName/1.0 (Android 14; Pixel 8)”。Accept-Language 从设备的系统语言中获取。根据 Alamofire(2026)的数据,通过 Interceptor 集中管理标头可将错误标头的数量减少 30%。

场景OkHttpAlamofire
日志记录HttpLoggingInterceptorEventMonitor
Auth tokenAuthenticator + InterceptorRequestInterceptor
标头addInterceptorRequestAdapter
Retry带重试的 InterceptorRequestRetrier
缓存CacheInterceptorCachedResponseHandler

最佳实践和链顺序

在 OkHttp 中添加 Interceptor 的顺序 决定了整个链的行为。第一个添加的拦截器在发送请求时第一个执行,在接收响应时最后一个执行。对于日志记录,首先添加 Interceptor — 它将看到带有来自其他拦截器的所有修改的最终请求。对于压缩 — 最后添加,以便压缩应用于最终数据。对于身份验证 — 在重试之前添加,以便令牌在重试之前刷新。

对生产构建的建议

在发布版本中,通过 BuildConfig.DEBUG 或依赖注入禁用日志记录。使用 addNetworkInterceptor 进行缓存 — Network Interceptor 可以看到服务器的 Cache-Control 标头并正确解释缓存策略。对于身份验证,使用 addInterceptor(Application)— 这可以防止在重定向到不应发送授权标头的外部域时再次拦截。使用 okhttp-testing-support 中的 MockWebServer 隔离测试每个 Interceptor — 它可以拦截请求并返回预先准备好的响应,从而允许在无实际服务器的情况下检查拦截器逻辑。

Interceptor 性能

每个 Interceptor 都会给请求时间增加少量延迟。在典型的 3–4 个拦截器链(日志记录、身份验证、压缩、缓存)中,每个请求的开销小于 5 毫秒。当 Interceptor 执行阻塞操作时,问题开始出现:同步刷新令牌 API 调用、将大日志写入文件或加密请求正文。所有这些操作都应该是异步的或在后台线程中执行。根据 Square(2026)的数据,OkHttp 在 Dispatcher 线程池中执行 Interceptor — 一个拦截器的阻塞会延迟整个链。

  • 顺序很重要 — 日志记录优先,身份验证在重试之前,压缩最后
  • 调试与发布 — HttpLoggingInterceptor 仅用于调试构建
  • 隔离 — 每个 Interceptor 解决一个任务(单一职责)
  • 异步性 — Interceptor 在 OkHttp 的后台线程上执行,不会阻塞 UI

常见问题

OkHttp 中 addInterceptor 和 addNetworkInterceptor 有什么区别?

addInterceptor(Application)在应用程序和 OkHttp 之间执行一次 — 看不到重定向和连接压缩。addNetworkInterceptor(Network)在 OkHttp 内部每次网络调用时执行 — 可以看到重定向、重试和压缩后的数据。日志记录和身份验证选择 Application,缓存选择 Network。

Interceptor 如何自动刷新令牌?

拦截器检查 response.code == 401,通过 Retrofit 或 URLSession 异步调用刷新令牌 API,保存新令牌并重试原始请求。在 OkHttp 中,对 Basic Auth 使用 Authenticator,对带刷新的 Bearer 使用 Interceptor。在 Alamofire 中 — retry 并检查错误类型。

Interceptor 会降低应用程序速度吗?

是的 — Interceptor 中的重型操作(记录大正文、加密、同步 API 调用)会增加响应时间。使用异步回调,通过 BuildConfig.DEBUG 仅限制调试构建的日志记录,不要在 intercept 方法中执行阻塞操作。

OkHttp 中的 Authenticator 是什么,与 Interceptor 有何不同?

Authenticator — 针对 401 响应的专用拦截器,实现 Basic Auth 或 Bearer 令牌。Authenticator 无法访问请求正文,也无法在发送前修改标头 — 只能处理带有授权错误的响应。而 Interceptor 可以在执行的任何阶段修改请求。

如何将同一个 Interceptor 添加到所有请求?

在 OkHttp 中,将 Interceptor 传递给 OkHttpClient.Builder — 来自该客户端的所有请求都通过它。在 Alamofire 中,将 RequestInterceptor 添加到 Session 配置中。如果您使用多个客户端(例如,用于不同的 API),请通过 Builder 模式创建一个带有通用拦截器的基本 Builder。

总结

  • Interceptor — 基于 Chain of Responsibility 模式的 HTTP 请求和响应拦截机制。
  • OkHttp 提供两种类型:Application(每个请求一次调用)和 Network(每次重定向和重试)。
  • Alamofire 在单个 RequestInterceptor 中分离适配(RequestAdapter)和重试(RequestRetrier)。
  • 主要场景 — 日志记录、身份验证、标头、重试和 HTTP 响应缓存。
  • Builder 中添加 Interceptor 的顺序 决定了顺序:日志记录 — 优先,压缩 — 最后。
  • 生产构建 需要通过 BuildConfig 标志和 DI 注入禁用调试日志记录。
  • 正确配置的拦截器链可将网络问题的调试时间缩短 40% 并标准化错误处理。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读