Retrofit 如何处理来自拦截器的无效响应?

How can Retrofit handle invalid responses from interceptor?

我花了好几个小时想弄明白这件事,但我仍然能弄明白。

我正在尝试使用 JSON 从网站检索数据。 如果网站是实时的并且一切正常,但如果网站 returns 除了数据之外的其他东西,比如 403 错误或任何其他错误,它就会崩溃。我尝试调试它,但我仍然不明白这里发生了什么。

这是我的代码:

我有一个带有拦截器的 NetworkModule,它应该检查响应是否有效,据我所知它是有效的,因为我的变量 isDataRetrievable 是 false(默认值):

val networkModule = module {

    single {

        val customGson =
            GsonBuilder().registerTypeAdapter(Lesson::class.java, LessonDeserializer())
                .create()

        Retrofit.Builder()
            .client(get())
            .addConverterFactory(
                GsonConverterFactory.create(customGson)
            )
            .baseUrl(BuildConfig.URL)
            .build()
    }

    factory {

        OkHttpClient.Builder()
            .addInterceptor(Interceptor { chain ->
                chain.withConnectTimeout(1,TimeUnit.SECONDS)
                val request: Request = chain.request()
                val response = chain.proceed(request)

                if (response.isSuccessful){
                    networkStatus.isDataRetrievable = true
                }

                response
            }).build()
    }

    factory {
        get<Retrofit>().create(LessonApi::class.java)
    }

}

接下来,我 API 获取数据:

interface LessonApi {
    @GET("/JSON/json_get_data.php")
    suspend fun getLessons(): Call<Lesson>
}

然后,出于某种原因,我有一个存储库(我不是唯一一个在处理这段代码的人,我没有做这部分):

class LessonRepository(private val service: LessonApi) {
    suspend fun getLessons() = service.getLessons()
}

然后,我有我的初始屏幕视图模型,如果可能的话应该检索数据:

          if (networkStatus.isNetworkConnected && networkStatus.isWebsiteReachable) {
                var tmp = repository.getLessons()
                tmp.enqueue(object : Callback<Lesson> {

                    override fun onFailure(call: Call<Lesson>, t: Throwable) {
                        Log.d("DataFailure",t.message.toString())
                        nextScreenLiveData.postValue(false)
                    }

                    override fun onResponse(call: Call<Lesson>, response: Response<Lesson>) {
                        Log.d("DataFailure","Test")
                    }
                })
            }else{
                nextScreenLiveData.postValue(false)
            }

问题是当程序到达行 repository.getLessons() 时,它崩溃并显示错误:

retrofit2.HttpException: HTTP 403 
        at retrofit2.KotlinExtensions$await.onResponse(KotlinExtensions.kt:49)
        at retrofit2.OkHttpCall.onResponse(OkHttpCall.java:129)
        at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
        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)

因此永远不会调用 onFailure 或 onResponse。我试图 运行 调试器介入,但当它失败时我无法弄清楚。 我以为是因为它试图反序列化无效数据,但我在我的反序列化器中到处都设置了断点,它从来没有遇到过断点。

我不是专业的android开发人员,但我在这里很困惑。

我想做的是,如果请求不成功,就丢弃响应(不要反序列化),并显示消息或退出。

请帮忙,这太令人沮丧了。我不确定如何拦截错误或如果拦截器收到不成功的请求该怎么办(现在我只是设置了一个变量但未使用)。

谢谢。

编辑: 我正在尝试做的是从网络服务器检索数据。如果它不能(出于任何原因),我不希望 gson 解析数据(因为它可能是垃圾并且不会对应于我的反序列化器)。但是,我觉得这个 okhttp / retrofit 是一个管道,其中 okhttp 从网络服务器获取响应并将其传递给 gson 转换器。我想要做的是拦截这个响应,如果它不成功,不要将它传递给 gson,设置一个变量,这样我的应用程序的其余部分就知道该怎么做。但问题是,就目前而言,它甚至在到达队列中的回调之前就崩溃了。拦截器工作得很好,除了我希望他在不成功时放弃响应。可能吗?

我尝试过类似的方法,它可以处理错误代码 (>400),但我还想处理格式错误的 JSON 数据,所以我添加了 onResponse 和 onFailure 回调,但它从未奏效,因为当我收到一个格式错误的JSON时,它也会触发一个异常,然后在catch中进去,然后才能继续'enqueue',所以我不确定这是做什么用的。

try {
    val lessons = repository.getLessons().enqueue(object : Callback<List<Lesson>> {
        override fun onResponse(call: Call<List<Lesson>>, response: Response<List<Lesson>>) {
            networkStatus.isDataRetrievable = response.isSuccessful
            Log.d("Retrofit", "Successful response")
            nextScreenLiveData.postValue(response.isSuccessful)
        }
    
        override fun onFailure(call: Call<List<Lesson>>, t: Throwable) {
            Log.d("Retrofit", "Failure response")
            nextScreenLiveData.postValue(false)
        }
    })
    nextScreenLiveData.postValue(true)
    } catch (e: Exception) {
    nextScreenLiveData.postValue(false)
    }

无论如何,只有这段代码最终适用于一切:

try {
    val lessons = repository.getLessons().filter {
        it.lesson.contains("video")
    }.filter {
        DataUtils.isANumber(it.id)
    }
    lessonDao.insertLessons(lessons)
    networkStatus.isDataRetrievable = true
} catch (e: Exception) {
    networkStatus.isDataRetrievable = false
}

但是在我的 API 中,我没有 return 回调,我直接 return 对象,例如:

@GET("/JSON/json_get_dat.php")
suspend fun getLessons(): List<Lesson>

我不知道这样做是否正确,但它确实有效。我希望这可能对其他人有所帮助。