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

Retrofit POST请求空响应体致Android App崩溃问题求助

相关代码

API代码

object RetrofitInstance {
    
    val nullOnEmptyConverterFactory = object : Converter.Factory() {
        fun converterFactory() = this
        override fun responseBodyConverter(type: Type, annotations: Array<out 
Annotation>, retrofit: Retrofit) = object : Converter<ResponseBody, Any?> {
            val nextResponseBodyConverter = retrofit.nextResponseBodyConverter<Any?> 
(converterFactory(), type, annotations)
            override fun convert(value: ResponseBody) = if (value.contentLength() != 0L) 
nextResponseBodyConverter.convert(value) else null
        }
    }
    
    val loggingInterceptor: HttpLoggingInterceptor = HttpLoggingInterceptor { message -> 
// Log the request URL
        println("$message")
    }.setLevel(Level.BODY)
    
    private val httpClient = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .build()
    
    private val retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(httpClient)
            .addConverterFactory(nullOnEmptyConverterFactory)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
    
    val api: API by lazy {
        retrofit.create(API::class.java)
    }

} 

MainViewModelFactory代码

class MainViewModelFactory(private val repository: Repository):  ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return MainViewModel(repository) as T
    } }

MainViewModel代码

fun pushClear(uniqueId: String, DELIVERED: Int = 0, delno: String) {
    viewModelScope.launch {
        val call = repository.pushClear(uniqueId, DELIVERED, delno)
        call.enqueue(object : Callback<Unit> {
            override fun onResponse(call: Call<Unit>, response: Response<Unit>){
            }
            override fun onFailure(call: Call<Unit>, t: Throwable) {
            }

        })
//            val response = repository.pushClear(uniqueId, DELIVERED, delno)
//            myPost6.value = response
    }
}

Repository代码

suspend fun pushClear(uniqueId: String, DELIVERED: Int = 0, delno: String): Call<Unit> {
    return RetrofitInstance.api.pushClear(uniqueId, DELIVERED, delno)
}

POST请求定义代码

@POST("/?q=8")
suspend fun pushClear(
    @Query("ID") uniqueId: String,
    @Query("p1") DELIVERED: Int = 0,
    @Query("p2") delno: String
): Call<Unit> 

POST请求调用代码

val repository = Repository()
val viewModelFactory = MainViewModelFactory(repository)
viewModel = ViewModelProvider(this, 
viewModelFactory).get(MainViewModel::class.java)
viewModel.pushClear(uniqueId,0, DELNO)         

解决方法

问题根源是自定义空响应转换器实现错误,以及suspend函数与Call返回值混用导致Retrofit解析空响应时抛出EOFException。按以下步骤修改:

1. 修复自定义空响应转换器

修正nullOnEmptyConverterFactory的实现,避免循环引用,正确处理空响应:

val nullOnEmptyConverterFactory = object : Converter.Factory() {
    override fun responseBodyConverter(type: Type, annotations: Array<out Annotation>, retrofit: Retrofit): Converter<ResponseBody, *>? {
        // 获取下一个转换器(即GsonConverter)
        val delegate = retrofit.nextResponseBodyConverter<Any>(this, type, annotations)
        return Converter { body ->
            if (body.contentLength() == 0L) {
                // 空响应返回null,跳过Gson解析
                null
            } else {
                // 非空响应交给Gson处理
                delegate.convert(body)
            }
        }
    }
}

2. 调整ConverterFactory的添加顺序

在Retrofit构建时,必须将自定义转换器放在Gson转换器之前,确保空响应先被拦截:

private val retrofit by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .client(httpClient)
        .addConverterFactory(nullOnEmptyConverterFactory) // 自定义转换器在前
        .addConverterFactory(GsonConverterFactory.create()) // Gson转换器在后
        .build()
}

3. 修正API接口的suspend函数返回值

Retrofit的suspend函数不需要返回Call<Unit>,直接返回Unit即可,异常通过抛出方式处理:

@POST("/?q=8")
suspend fun pushClear(
    @Query("ID") uniqueId: String,
    @Query("p1") DELIVERED: Int = 0,
    @Query("p2") delno: String
): Unit

4. 更新Repository代码

去掉返回值Call<Unit>,直接调用接口方法:

suspend fun pushClear(uniqueId: String, DELIVERED: Int = 0, delno: String) {
    RetrofitInstance.api.pushClear(uniqueId, DELIVERED, delno)
}

5. 修改ViewModel中的调用逻辑

用try-catch捕获异常,替代enqueue回调(suspend函数无需手动处理异步):

fun pushClear(uniqueId: String, DELIVERED: Int = 0, delno: String) {
    viewModelScope.launch {
        try {
            repository.pushClear(uniqueId, DELIVERED, delno)
            // 这里添加请求成功后的逻辑,比如更新UI、提示用户等
        } catch (e: Exception) {
            // 处理异常,比如网络错误、解析错误等
            e.printStackTrace()
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:40:07