Retrofit 2.0とRxJavaを使用して応答ステータスコードを取得する


107

Retrofit 2.0にアップグレードして、AndroidプロジェクトにRxJavaを追加しようとしています。私はAPI呼び出しを行っており、サーバーからのエラー応答の場合にエラーコードを取得したいと考えています。

Observable<MyResponseObject> apiCall(@Body body);

そしてRxJava呼び出しで:

myRetrofitObject.apiCall(body).subscribe(new Subscriber<MyResponseObject>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(MyResponseObject myResponseObject) {
           //On response from server
        }
    });

Retrofit 1.9では、RetrofitErrorがまだ存在しており、次のようにしてステータスを取得できます。

error.getResponse().getStatus()

RxJavaを使用してRetrofit 2.0でこれをどのように行いますか?

回答:


185

あなたがしたようにAPI呼び出しを宣言する代わりに:

Observable<MyResponseObject> apiCall(@Body body);

次のように宣言することもできます:

Observable<Response<MyResponseObject>> apiCall(@Body body);

その後、次のようなサブスクライバーが作成されます。

new Subscriber<Response<StartupResponse>>() {
    @Override
    public void onCompleted() {}

    @Override
    public void onError(Throwable e) {
        Timber.e(e, "onError: %", e.toString());

        // network errors, e. g. UnknownHostException, will end up here
    }

    @Override
    public void onNext(Response<StartupResponse> startupResponseResponse) {
        Timber.d("onNext: %s", startupResponseResponse.code());

        // HTTP errors, e. g. 404, will end up here!
    }
}

したがって、エラーコードを含むサーバー応答もに配信されonNext、を呼び出すことでコードを取得できますreponse.code()

http://square.github.io/retrofit/2.x/retrofit/retrofit/Response.html

編集: OK、私はようやく、e-nouriがコメントで言ったこと、つまり、2xxコードのみがにアクセスできることを調べましたonNext。どちらも正しいことがわかりました。

呼び出しが次のように宣言されている場合:

Observable<Response<MyResponseObject>> apiCall(@Body body);

それとも

Observable<Response<ResponseBody>> apiCall(@Body body);

onNextエラーコードに関係なく、すべての応答は最終的にになります。すべてがResponseレトロフィットによってオブジェクトに包まれているため、これは可能です。

一方、呼び出しが次のように宣言されている場合:

Observable<MyResponseObject> apiCall(@Body body);

またはこれ

Observable<ResponseBody> apiCall(@Body body);

実際、2xx応答のみがに送信されonNextます。その他はすべてにラップされてHttpExceptionに送信されonErrorます。どちらも意味がありResponseます。ラッパーがなければ、何に出力する必要があるのonNextですか?リクエストが成功しなかったとすると、放出するのは賢明なことだけnullです...


16
HTTPコード4xxを探している人々にとって、それらは最終的にonErrorのHttpExceptionになります。onNextには2xxのみが含まれます。
e-nouri 2016年

2
それは興味深い...もう一度チェックしたところ(gist.github.com/DavidMihola/17a6ea373b9312fb723b)、試したコードはすべてonNext404などを含めてしまいました。Retrofitv2.0.0-beta3を使用しました。
david.mihola

@ e-nouri:私はあなたのコメントを考慮に入れた段落を私の回答に追加しました!
david.mihola 2016年

1
@ david.mihola addを使用してレトロフィットを構築する場合GsonConverterFactory、同じRetrofit retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create())ように、元の応答を取得するにはどうすればよいですか?
Honghe.Wu

1
エラー処理とは別に、本文に付属する応答ヘッダーを検査できるようにしたいと思うかもしれませんResponse。これは、を取得した場合にのみ可能です。私もめったにそれを使用しません-それが存在することを知るのは良いことだと思います。
david.mihola 2017

112

onErrorメソッド内にこれを入れてコードを取得します

((HttpException) e).code()

7
これは、私がSOでこれまでに見た中で最も過小評価されている答えの1つかもしれません。これは天才です。を使用して、応答で実行する必要があるすべてのことを実行できますHttpException。私はRxJavaを使用していて、を受け取った後に応答を解析する必要がありましたHTTP 400 BAD REQUEST。どうもありがとうございました!
GabrielOshiro 2016

29
NetworkErrorsはIOExceptionsになり、ステータスコードがないため、前にHttpExceptionのインスタンスかどうかを確認してください。
Benjamin Mesing 2017

@BenjaminMesingから続くと、NetworkErrorについて述べました、サブスクライブする前にRxでより多くのダウンストリームオペレーター(map / flatMap / forEachなど)を実行している場合、例外タイプのホストが存在する可能性があり、必ずしもエラーではありませんネットワーク要求。
マークキーン

java.lang.ClassCastException:java.lang.Throwableをretrofit2.HttpExceptionにキャストできません
誰かのどこか

7

あなたがのように注意する必要がありRetrofit2コードを持つすべての応答の2xxは onNext()コールバックとの残りの部分から呼び出されるHTTPコードの4xxのような、5xxのは、上で呼び出されるのonError()使用して、コールバックKotlinのIてきたのような何かを思い付きましたこれはonError()で

mViewReference?.get()?.onMediaFetchFinished(downloadArg)
  if (it is HttpException) {
    val errorCode = it.code()
    mViewReference?.get()?.onMediaFetchFailed(downloadArg,when(errorCode){
      HttpURLConnection.HTTP_NOT_FOUND -> R.string.check_is_private
      else -> ErrorHandler.parseError(it)
    })
  } else {
    mViewReference?.get()?.onMediaFetchFailed(downloadArg, ErrorHandler.parseError(it))
  }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.