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

Retrofit返回Response<Void>时非200状态码不触发异常的注解方案问询

解决Retrofit返回Response时非200状态码不触发异常的问题

Retrofit本身没有内置注解能让返回Response类型的接口自动抛出包含Response对象的异常——因为Retrofit的设计逻辑就是:当方法返回Response时,无论HTTP状态码是否成功,都会将结果封装为Response对象返回,不会主动抛出HttpException,所以你的catch分支无法触发。

不过可以通过以下两种方式实现需求:

1. 手动判断状态码,主动抛出异常

这是最直接的方式,在调用接口后手动检查Response.isSuccessful,如果为false就抛出Retrofit自带的HttpException(该类内部持有原始的Response对象):

try {
    val response = sendTest(testModel)
    if (!response.isSuccessful) {
        throw HttpException(response)
    }
    // 处理成功逻辑
} catch (e: HttpException) {
    // 在这里通过e.response()获取原始Response
    val errorResponse = e.response()
    // 处理错误逻辑
}

2. 自定义注解+CallAdapter,实现全局/按需自动抛异常

如果想让指定接口自动在非成功状态码时抛异常,可以自定义一个注解,配合自定义CallAdapter.Factory来实现:

步骤1:定义自定义注解

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class ThrowOnError

步骤2:实现自定义CallAdapter.Factory

这个CallAdapter会拦截接口调用,判断方法是否带有@ThrowOnError注解,若是则在非成功状态码时自动抛出HttpException:

class ThrowOnErrorCallAdapterFactory : CallAdapter.Factory() {
    override fun get(
        returnType: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): CallAdapter<*, *>? {
        // 先获取Retrofit默认的CallAdapter
        val delegate = retrofit.nextCallAdapter(this, returnType, annotations)
        // 判断当前接口方法是否带有@ThrowOnError注解
        val shouldThrow = annotations.any { it is ThrowOnError }

        return object : CallAdapter<Any, Call<Any>> {
            override fun responseType(): Type = delegate.responseType()

            override fun adapt(call: Call<Any>): Call<Any> {
                return object : Call<Any> by call {
                    // 处理挂起函数的await逻辑
                    override suspend fun await(): Any {
                        val response = call.await()
                        if (shouldThrow && response is Response<*> && !response.isSuccessful) {
                            throw HttpException(response as Response<*>)
                        }
                        return response
                    }

                    // 处理传统的enqueue回调逻辑(如果有用到的话)
                    override fun enqueue(callback: Callback<Any>) {
                        call.enqueue(object : Callback<Any> {
                            override fun onResponse(call: Call<Any>, response: Response<Any>) {
                                if (shouldThrow && !response.isSuccessful) {
                                    callback.onFailure(call, HttpException(response))
                                } else {
                                    callback.onResponse(call, response)
                                }
                            }

                            override fun onFailure(call: Call<Any>, t: Throwable) {
                                callback.onFailure(call, t)
                            }
                        })
                    }
                }
            }
        }
    }
}

步骤3:在Retrofit构建时添加该CallAdapterFactory

val retrofit = Retrofit.Builder()
    .baseUrl("your_base_url")
    .addCallAdapterFactory(ThrowOnErrorCallAdapterFactory())
    .addConverterFactory(GsonConverterFactory.create())
    .build()

步骤4:在接口方法上添加自定义注解

@POST("/test")
@ThrowOnError
suspend fun sendTest(@Body model: TestModel): Response<Void>

这样,当这个接口返回非200状态码时,会自动抛出HttpException,你可以在catch分支中通过e.response()拿到原始的Response对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 17:25:59