【问题标题】:Kotlin RxJava2 onError not called for Http status code 400Kotlin RxJava2 onError 未调用 Http 状态代码 400
【发布时间】:2019-01-20 07:34:09
【问题描述】:

我在我正在开发的 Android 应用程序中使用带有 Retrofit 和 OkHttp 的 RxJava2。

对于这个应用程序,我使用的是 Kotlin,并不是说它是 Java 还是 Kotlin 有什么区别。

在我之前开发的应用程序中,当服务器返回 400 错误代码时,会调用 onError 回调。然而,今天在处理此设置时,onError 回调仅在服务器关闭但 onNext 被调用时触发,即使是 400 错误代码。

以下是我设置的摘录

/**
 * Networking
 */
implementation "com.squareup.okhttp3:okhttp:3.11.0"
implementation "com.squareup.okhttp3:logging-interceptor:3.11.0"
implementation "com.squareup.retrofit2:retrofit:2.4.0"
implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
/**
 * Rx
 */
implementation "io.reactivex.rxjava2:rxandroid:2.0.2"
implementation "io.reactivex.rxjava2:rxkotlin:2.2.0"

这是实际构建改造对象的 dagger2 模块的摘录

    @Singleton
    @Provides
    fun provideRetrofit(okHttpClient: OkHttpClient,
                        gson: Gson,
                        @BaseUrl baseUrl: String): Retrofit {
        return Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(baseUrl)
                .client(okHttpClient)
                .build()
    }

这是调用 API 的实际代码

fun loginUser(username: String, password: String): MutableLiveData<Result> {
        if (username.isNotBlank() && password.isNotBlank()) {
            subscriptions.addAll(remoteUserRepository
                    .getUser(UserDto(username, password))
                    .subscribeBy(onNext = {
                        saveUser(it.body())
                        saveAuthenticationToken(it.headers().get("token"))
                    }, onError = { handleError(it) }))
        }
        return resultLiveData
    }

    private fun saveUser(user: User?) {
        user?.let {
            localUserRepository.saveUser(it)
            resultLiveData.value = Result.SUCCESS
        }
    }

    private fun saveAuthenticationToken(token: String?) {
        token?.let { localUserRepository.saveToken(it) }
    }

    override fun handleError(error: Throwable) {
        super.handleError(error)
        resultLiveData.value = Result.FAILURE
    }

这是来自服务器的请求和响应的日志,清楚地表明服务器正在返回 http 代码 401

   D/OkHttp: --> POST http://10.0.2.2:3000/login http/1.1
    Content-Type: application/json; charset=UTF-8
D/OkHttp: Content-Length: 48
    Host: 10.0.2.2:3000
    Connection: Keep-Alive
    Accept-Encoding: gzip
    User-Agent: okhttp/3.11.0
    --> END POST
D/OkHttp: <-- 401 Unauthorized http://10.0.2.2:3000/login (20ms)
    content-type: application/json; charset=utf-8
    cache-control: no-cache
    content-length: 94
    Date: Mon, 13 Aug 2018 13:55:07 GMT
    Connection: keep-alive
    <-- END HTTP

即使服务器返回 401 错误,handleError(error: Throwable) 回调也不会被调用。只有在服务器无法访问时才会调用它。

我错过了什么?

【问题讨论】:

  • onError 仅针对错误调用。虽然就数据而言,4xx 代表一个不成功的调用,但它并非自然错误。您可以使用Response&lt;T&gt;#isSuccessful() 区分成功回调(onNext 或其他)中的成功和不成功调用
  • @TimCastelijns 它是如何在这里完成的:medium.com/mindorks/… 加上我记得在 RxJava1 中 onError 也被称为 400 状态代码响应。你知道这种行为是否改变了吗?
  • 如您所见,您链接到的此示例仅处理调用本身的错误,而不是传输数据的“错误”
  • 但他正在检查if (e instanceof HttpException),这会发生传输错误,还是我弄错了?
  • 自己检查是最简单的。附加调试器,触发 401 响应,看看会发生什么

标签: android kotlin retrofit rx-java2 okhttp3


【解决方案1】:

onError 确实会捕获由于执行任务或处理结果而发生的错误。

在你的情况下,改造电话是可以的。

您必须处理响应的结果: 在您的 onSuccess 中检查是否响应 isSuccessful 并继续

【讨论】:

    【解决方案2】:

    事实证明,所面临的行为是正确的,原因如下:

    @POST("/login")
    fun login(@Body userDto: UserDto): Observable<Response<User>>
    

    如你所见,函数的返回类型是Observable&lt;Response&lt;User&gt;&gt;,更准确地说是Response&lt;User&gt;

    因此,无论 http 状态代码如何,只要收到响应,就会调用 onNext。唯一一次在无法收到响应时调用onError

    因此,如果您想要返回Response,则需要使用@MaxAves 建议的方法

    如果您希望在服务器返回 400 错误代码时调用 onError,则需要修改接口,使其如下所示:

    @POST("/login")
    fun login(@Body userDto: UserDto): Observable<User>
    

    在我的情况下,这是不可行的,因为我需要访问响应标头。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-01
      • 1970-01-01
      • 2012-05-30
      • 2022-01-20
      • 2012-09-17
      • 2021-01-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多