Retrofit2 обрабатывает ситуацию HTTP 204 (без ответа на контент) с наблюдаемыми концепциями RxJava - PullRequest
0 голосов
/ 17 мая 2018

У меня есть веб-сервис, который возвращает список пользователей по теме, если нет пользователя для этой темы, он просто возвращает HTTP-код 204 (без содержимого).

Это мой призыв к модернизации2 для этой услуги (в Котлине)

@GET("/user/{topic}")
fun getAllUserFor(@Path(value="topic",encoded=true) topic:String) :Observable<List<User>>

И мое исполнение:

fun getAllUsers(topic: String, onSuccess: Consumer<List<User>>, onFail:Consumer<Throwable>){

    val api = NetworkLayer.getUserApi()

    api.getAllUserFor(topic)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe(onSuccess,onFail)

}

Работает нормально, за исключением случаев, когда в теме нет пользователей, поскольку при отсутствии пользователей сервер отвечает кодом 204, полученным в качестве исключения.

Я использую ScalarsConverterFactory & GsonConverterFactory для анализа ответа Json с Retrofit2.

аналогичная проблема обсуждалась здесь но их сервер отвечает только http кодом без какого-либо контента! В моем случае сервер вернет список пользователей в виде тела Json, когда есть один или несколько пользователей, и ответ 204, когда нет пользователей, поэтому мне нужно обработать оба случая вместе с другими обычными ошибками http.

Ответы [ 2 ]

0 голосов
/ 30 июля 2018

Стандартный способ заключает в себе ответ в Result, который поставляется с зависимостью adapter-rxjava2.

        @GET("/user/{topic}")
        fun getAllUserFor(@Path(value="topic",encoded=true) topic:String) :Observable<Result<List<User>>>

таким образом, ошибки также доставляются на ваш следующий, и вы можете сделать что-то вроде этого:

           api.getAllUserFor(topic)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe{ result ->
               if(result.isError)
                   //Network Error
               result.response()?.also {
                   if(result.isSuccessful)
                       //Success
                   else{
                       //api error
                   }
            }
          }

намного чище и лаконичнее

проверка статуса с

result.response?.code()

ура!

0 голосов
/ 17 мая 2018

Этого можно добиться, внедрив оператора, который проверяет, равен ли код состояния полученного ответа 204:

class OnApiErrorOperator : ObservableOperator<OnApiErrorOperator.User, Response<OnApiErrorOperator.User>> {

    override fun apply(observer: Observer<in OnApiErrorOperator.User>): Observer<in Response<OnApiErrorOperator.User>> {
        return object : Observer<Response<OnApiErrorOperator.User>> {

            override fun onSubscribe(d: Disposable) {
                observer.onSubscribe(d)
            }

            override fun onNext(response: Response<OnApiErrorOperator.User>) {
                if (response.code() == 204) {
                    //return User object with empty list when response's status code is 204
                    observer.onNext(User(emptyList()))
                } else {
                    if (response.isSuccessful) {
                        observer.onNext(response.body()!!)
                    } else {
                        //don't forget to check for other statuses
                        observer.onError(OnApiServerErrorException(response.code()))
                    }
                }
            }

            override fun onError(e: Throwable) {
                observer.onError(e)
            }

            override fun onComplete() {
                observer.onComplete()
            }
        }
    }

    class User(
            @SerializedName("user_info")
            val userInfo: List<String>
    )

    class OnApiServerErrorException(val statusCode: Int) : Exception()
}

И затем вы можете добавить оператор lift в цепочке наблюдаемых, чтобы вызвать его:

api.getAllUserFor(topic)
        .subscribeOn(Schedulers.io())
        .lift(OnApiErrorOperator())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(onSuccess, onFail)
...