如何使用 Kotlin 协程在 Retrofit 中处理 204 响应?

Phi*_*lly 18 android retrofit retrofit2 kotlin-coroutines

我正在使用带有 Kotlin 协程的 Retrofit 2.7.1。

我有一个 Retrofit 服务定义如下:

@PUT("/users/{userId}.json")
suspend fun updateUserProfile(
        @Path("userId") userId: String,
        @Query("display_name") displayName: String) : Void
Run Code Online (Sandbox Code Playgroud)

此调用返回HTTP 204 No Content响应,这会导致 Retrofit 崩溃:

kotlin.KotlinNullPointerException: Response from com.philsoft.test.api.UserApiService.updateUserProfile was null but response body type was declared as non-null
        at retrofit2.KotlinExtensions$await$2$2.onResponse(KotlinExtensions.kt:43)
        at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:129)
        at okhttp3.RealCall$AsyncCall.execute(RealCall.java:174)
        at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)
Run Code Online (Sandbox Code Playgroud)

如何在改造中使用协程处理 204 响应而不会崩溃?

Dmi*_*tri 43

据此,Response<Unit>在改造方法声明中使用。

改造没有内容问题

  • 我在这个问题上花了将近2天的时间,最后它与你的解决方案配合得很好。谢谢。 (3认同)
  • 如果 API 可以返回 null 或非 null 值,则此解决方案将不起作用。 (3认同)

sav*_*ion 10

您可以使用Response<Unit>来处理 204 个响应,Retrofit但是当您像这样处理时,Retrofit不会为4xx响应或其他异常情况抛出异常。

您可以使用以下代码处理这些情况:

return try {
        val result = apiCall.invoke()
        return if (result is Response<*>) {
            if (result.code() >= 400) {
                // create an error from error body and return
            } else {
                // return success result
            }
        } else {
            // directly return success result
        }
    } catch (t: Throwable) {
        // create an error from throwable and return it!
    }
Run Code Online (Sandbox Code Playgroud)


Kis*_*nki 6

用示例代码解释@Dmitri 的答案:

  1. 在您的 APIInterface 中,像这样调用您的 API,

     @GET(AppConstants.APIEndPoints.GET_NEWS)
     suspend fun getNews(
         @Query("limit") limit: String,
     ): Response<NewsListResponseModel>
    
    Run Code Online (Sandbox Code Playgroud)

其中,响应是 retrofit2.Response

  1. 从调用 API 的位置,检查来自函数的状态代码,例如apiResponse.code().

    val apiResponse = apiEndPointsInterface.getNews(limit)
    if (apiResponse.code() == HttpURLConnection.HTTP_OK) {
         //response success
         ResultOf.Success(apiResponse.body()!!))
     } else {
         //something went wrong
         ResultOf.Failure("No Data Found.", null))
     }
    
    Run Code Online (Sandbox Code Playgroud)


flo*_*hot 5

204使用自定义拦截器将's更改为200's 对我有用

class Code204Interceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val response = chain.proceed(request)

        return if (response.code == 204) {
            response.newBuilder().code(200).build()
        } else {
            response
        }
    }
}
Run Code Online (Sandbox Code Playgroud)