You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中用ByteBuddy拦截OkHttp请求响应报错及方案咨询

问题分析与解决方案

异常原因

你遇到的IllegalStateException是因为方法匹配器存在冗余语法错误:

  • named<MethodDescription?>("newCall")中的泛型参数完全多余,会导致ByteBuddy的匹配逻辑异常
  • 后续添加的not(named("-deprecated_authenticator"))和not(isDeclaredBy(Authenticator::class.java))属于画蛇添足——named("newCall")已经精准匹配目标方法,这些排除条件不会过滤任何有效内容,反而干扰了ByteBuddy的方法扫描逻辑,误匹配到OkHttpClient内部的-deprecated_authenticator()方法(该方法名包含特殊字符,ByteBuddy无法正常处理)。

正确的ByteBuddy拦截实现

如果需要全局拦截所有OkHttp请求(包括第三方库创建的客户端),可以通过拦截Call接口的execute()(同步请求)和enqueue()(异步请求)方法实现,这比拦截OkHttpClient.newCall()更全面:

1. 初始化ByteBuddy(建议在Application中执行)

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        setupByteBuddyInterceptor()
    }

    private fun setupByteBuddyInterceptor() {
        try {
            ByteBuddy()
                .redefine(Call::class.java)
                // 匹配Call接口的execute和enqueue方法
                .method(named("execute").or(named("enqueue")))
                .intercept(MethodDelegation.to(OkHttpCallInterceptor::class.java))
                .make()
                .load(
                    this.classLoader,
                    AndroidClassLoadingStrategy.Wrapping(this.filesDir)
                )
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

2. 实现拦截器类

class OkHttpCallInterceptor {
    // 拦截同步请求execute方法
    @RuntimeType
    fun interceptExecute(
        @This call: Call,
        @Origin method: Method
    ): Response {
        // 捕获请求信息
        val request = call.request()
        println("[Sync Request] URL: ${request.url}")
        println("[Sync Request] Headers: ${request.headers}")

        // 执行原方法获取响应
        val originalResponse = method.invoke(call) as Response

        // 捕获响应信息(注意:body.string()会消耗流,需重新构建响应)
        val responseBody = originalResponse.body?.string()
        println("[Sync Response] Code: ${originalResponse.code}")
        println("[Sync Response] Body: $responseBody")

        // 重新构建响应,避免后续拦截器/业务逻辑无法读取body
        val newResponseBody = responseBody?.let {
            ResponseBody.create(originalResponse.body?.contentType(), it)
        }
        return originalResponse.newBuilder().body(newResponseBody).build()
    }

    // 拦截异步请求enqueue方法
    @RuntimeType
    fun interceptEnqueue(
        @This call: Call,
        @Origin method: Method,
        @AllArguments args: Array<Any>
    ) {
        if (args.isNotEmpty() && args[0] is Callback) {
            val originalCallback = args[0] as Callback
            val request = call.request()

            // 捕获异步请求信息
            println("[Async Request] URL: ${request.url}")
            println("[Async Request] Headers: ${request.headers}")

            // 包装Callback,捕获响应
            val wrappedCallback = object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                    println("[Async Request Failed] ${e.message}")
                    originalCallback.onFailure(call, e)
                }

                override fun onResponse(call: Call, response: Response) {
                    val responseBody = response.body?.string()
                    println("[Async Response] Code: ${response.code}")
                    println("[Async Response] Body: $responseBody")

                    // 重新构建响应
                    val newResponseBody = responseBody?.let {
                        ResponseBody.create(response.body?.contentType(), it)
                    }
                    val newResponse = response.newBuilder().body(newResponseBody).build()
                    originalCallback.onResponse(call, newResponse)
                }
            }

            // 调用原方法,传入包装后的Callback
            method.invoke(call, wrappedCallback)
        } else {
            // 异常情况直接执行原方法
            method.invoke(call, *args)
        }
    }
}

关于自定义OkHttp客户端的方案

完全可以使用OkHttpClient.Builder().addInterceptor()的方式实现请求拦截,这是OkHttp官方推荐的方案,具备以下优势:

  • 实现简单,无需字节码操作,调试成本低
  • 兼容性好,不受Android版本、混淆规则的限制
  • 可以灵活控制拦截范围(仅拦截自己创建的客户端实例)

示例代码

class LoggingInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val startTime = System.nanoTime()

        // 打印请求信息
        println("Sending request: ${request.url}")
        println("Request Headers: ${request.headers}")

        // 执行请求获取响应
        val response = chain.proceed(request)

        // 打印响应信息
        val durationMs = (System.nanoTime() - startTime) / 1e6
        println("Received response for ${response.request.url} in ${durationMs}ms")
        println("Response Code: ${response.code}")

        // 处理响应body(同样需要重新构建)
        val responseBody = response.body?.string()
        println("Response Body: $responseBody")
        val newResponseBody = responseBody?.let {
            ResponseBody.create(response.body?.contentType(), it)
        }
        return response.newBuilder().body(newResponseBody).build()
    }
}

// 使用方式
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(LoggingInterceptor())
    .build()

两种方案对比

方案类型优点缺点
ByteBuddy字节码拦截全局拦截所有OkHttpClient实例的请求涉及字节码操作,兼容性/调试难度高
OkHttp官方Interceptor简单稳定,官方支持,兼容性好仅能拦截自己创建的客户端实例

内容的提问来源于stack exchange,提问作者sam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 05:44:50