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>
我不知道这样做是否正确,但它确实有效。我希望这可能对其他人有所帮助。
我花了好几个小时想弄明白这件事,但我仍然能弄明白。
我正在尝试使用 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>
我不知道这样做是否正确,但它确实有效。我希望这可能对其他人有所帮助。