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

OkHttp MockWebServer的dispatch方法未触发问题求助

问题原因及解决方案

核心问题在于MockWebServer是函数内的局部变量:

  • 函数getMockServerUrl()执行时,启动MockWebServer并创建Retrofit实例,随后启动新线程发起异步请求,紧接着函数就返回URL并执行完毕。
  • 此时server作为局部变量,没有任何外部强引用持有它,会被Java/Kotlin的垃圾回收器(GC)标记为可回收对象,大概率在异步请求真正发起前就被销毁,MockWebServer随之停止服务。

这就解释了你的现象:

  • 外部浏览器访问是在函数执行过程中(server还存活时)发起的,所以能触发dispatch方法;
  • Retrofit的异步请求在新线程中执行,当它真正发送请求时,server已经被回收、服务停止,请求根本没到达MockWebServer,自然不会打印dispatch hit 🚀;而Response is null是因为请求连接失败,你的回调只实现了onResponse,框架在错误场景下返回了空响应体。

修复方案

方案1:延长MockWebServer的生命周期

将server从局部变量改为类成员变量,确保它在异步请求完成前不会被GC回收:

// 类成员变量
private lateinit var server: MockWebServer

fun getMockServerUrl(): String {
    server = MockWebServer()
    server.dispatcher = object : Dispatcher() {
        override fun dispatch(request: RecordedRequest): MockResponse {
            println("dispatch hit 🚀")
            // 替换TODO()为实际的MockResponse
            return MockResponse().setBody("mock data")
        }
    }
    server.start()
    val url = server.url(path = "")

    val api = Retrofit.Builder()
        .baseUrl(url)
        // 补充你的ConverterFactory、CallAdapterFactory等配置
        .addConverterFactory(ScalarsConverterFactory.create())
        .create(MyApi::class.java)

    Thread {
        api.getData().enqueue(
            object : Callback<String> {
                override fun onResponse(call: Call<String>, response: Response<String>) {
                    println("Response is ${response.body()}")
                    // 请求完成后可按需停止服务器
                    // server.shutdown()
                }

                // 实现onFailure方便排查错误
                override fun onFailure(call: Call<String>, t: Throwable) {
                    println("Request failed: ${t.message}")
                    // server.shutdown()
                }
            },
        )
    }.start()

    return url.toString().also {
        println("URL is $it")
    }
}

方案2:同步等待请求完成(仅用于测试场景)

如果这是测试代码,可以用CountDownLatch让主线程等待异步请求完成后再返回,避免server被提前回收:

import java.util.concurrent.CountDownLatch

fun getMockServerUrl(): String {
    val server = MockWebServer()
    server.dispatcher = object : Dispatcher() {
        override fun dispatch(request: RecordedRequest): MockResponse {
            println("dispatch hit 🚀")
            return MockResponse().setBody("mock data")
        }
    }
    server.start()
    val url = server.url(path = "")

    val api = Retrofit.Builder()
        .baseUrl(url)
        .addConverterFactory(ScalarsConverterFactory.create())
        .create(MyApi::class.java)

    val latch = CountDownLatch(1)

    Thread {
        api.getData().enqueue(
            object : Callback<String> {
                override fun onResponse(call: Call<String>, response: Response<String>) {
                    println("Response is ${response.body()}")
                    latch.countDown()
                    server.shutdown()
                }

                override fun onFailure(call: Call<String>, t: Throwable) {
                    println("Request failed: ${t.message}")
                    latch.countDown()
                    server.shutdown()
                }
            },
        )
    }.start()

    // 等待请求完成
    latch.await()

    return url.toString().also {
        println("URL is $it")
    }
}

注意:原代码中dispatch方法的TODO()会抛出异常,记得替换为返回合法的MockResponse,否则即使请求到达服务器,也会返回错误响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 19:25:57