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
相关产品推荐
相关产品推荐

