web-dev-qa-db-ja.com

Retrofitを使用してRetrofitErrorオブジェクトからJSONを取得する

Retrofitライブラリを使用して、REST使用しているサービスへの呼び出しを行います。

サービスに対してAPI呼び出しを行って失敗した場合、サービスは標準のHTTPエラーと一緒に少しのJSONを返します。失敗コールバックに含まれるRetrofitErrorオブジェクトを使用すると、HTTPステータスコードと他のいくつかのものを見つけることができますが、サービスが送り返すJSONを取得することはできません。

たとえば、ユーザーを作成しようとしているAPIを呼び出したとします。ユーザー名が既に存在する場合、サービスは次のようなJSONとともに400エラーコードを返します。

{"error":"Username already in use"}

単純な400エラーコードでは十分に具体的ではないため、返されるJSONにアクセスする必要があります。

誰もがこのJSONデータをどのように取得できるか知っていますか? RetrofitErrorオブジェクトのすべてのフィールドを調べてみましたが、どこにも見つかりません。他に何かする必要があることはありますか?

39
neonDion

RetrofitErrorオブジェクトの getBodyAs メソッドを使用できます。他のRetrofit変換と同様に、応答をJavaオブジェクトに変換します。まず、JSONエラー応答を記述するクラスを定義します。

class RestError {
    @SerializedName("code")
    public int code;
    @SerializedName("error")
    public String errorDetails;
}

次に、前述のメソッドを使用して、エラーを詳細に説明するオブジェクトを取得します。

catch(RetrofitError error) {
    if (error.getResponse() != null) {
        RestError body = (RestError) error.getBodyAs(RestError.class);
        log(body.errorDetails);
        switch (body.code) {
            case 101:
                ...
            case 102:
                ...
        }
    }
}

Retrofit 2.0は、エラー応答の変換方法を変更しました。 responseBodyConverter メソッドで正しいコンバーターを取得し、それを使用して応答のエラー本文を変換する必要があります。これを処理する例外がなければ、次のようになります。

Converter<ResponseBody, RestError> converter 
    = retrofit.responseBodyConverter(RestError.class, new Annotation[0]);
RestError errorResponse = converter.convert(response.errorBody());
103
LukaCiko

このコードを試してください

@Override
public void failure(RetrofitError error) {
    String json =  new String(((TypedByteArray)error.getResponse().getBody()).getBytes());
    Log.v("failure", json.toString());
}

Retrofit 2.

@Override
public void onFailure(Call<Example> call, Throwable t) {
    String message = t.getMessage();
    Log.d("failure", message);
}
20
Cabezas

JSONオブジェクトを取得するためのgetBodyAs付きの2ライナー。

JsonObject responseAsJson = (JsonObject) retrofitError.getBodyAs(JsonElement.class);

String message = responseAsJson.get("error").getAsString(); //=> "Username already in use"

Retrofit 1.xでの動作を確認しました。 Retrofit 2.xに必要な変更はわかりません。

5
JaredBanyard

@LukaCikoの答えは、レトロフィット1.6.1では今は機能していません。ここで私が今やっているように:

    @Override
    public void failure(RetrofitError retrofitError) {
        String json =  new String(((TypedByteArray)retrofitError.getResponse().getBody()).getBytes());
        //own logic for example
        ExampleHandlerError error = new Gson().fromJson(json, ExampleHandlerError.class);
    }
5
ar-g

これを使用すると、エラー本文を取得できます

  if (response != null && response.errorBody() != null) {
    JSONObject jsonObject = new JSONObject(response.errorBody().string());
    String error =  jsonObject.getString("error");
  }
1
Amit Shekhar

これを行うための非常にすてきな方法は、いつでもどこでも呼び出すことができる、あなたのために解析/変換を行うことができるクラスを作成することです。

public class ApiError {
    public String error = "An error occurred";

    public ApiError(Throwable error) {
        if (error instanceof HttpException) {
            String errorJsonString = null;
            try {
                errorJsonString = ((HttpException) 
                error).response().errorBody().string();
            } catch (IOException e) {
                e.printStackTrace();
            }
            JsonElement parsedString = new 
            JsonParser().parse(errorJsonString);
            this.error = parsedString.getAsJsonObject()
                                     .get("error")
                                     .getAsString();
        } else {
            this.error = error.getMessage() != null ? error.getMessage() : this.error;
        }
    }
}

これをどこでも使用できるようになりました

ApiError error = new ApiError(error)
error.error

これはすべて このブログ投稿 (私が書いた)からです。

1
Timi Ajiboye

それで、もう少し狩りをして、答えを見つけました。

ここに私の失敗のコールバックがあります:

@Override public void failure(RetrofitError retrofitError) {
    String serverError = null;
    try {
        serverError = extractServerError(retrofitError.getResponse().getBody().in());
    } catch (Exception e) {
        Log.e("LOG_TAG", "Error converting RetrofitError server JSON", e);
    }

    if (serverError!=null) {
        Log.i(LOG_TAG, serverError);
    }

    Intent intent = new Intent(ACTION_REGISTRATION_ERROR);
    intent.putExtra("ServerError", serverError);
    LocalBroadcastManager.getInstance(FamDooApplication.CONTEXT).sendBroadcastSync(intent);
}

サーバーエラーを抽出するために呼び出されるメソッドは次のとおりです。

public static String extractServerError(Java.io.InputStream is) {
    String serverError = null;
    String serverErrorDescription = null;
try {

    String s = convertStreamToString(is);

    JSONObject messageObject = new JSONObject(s);
    serverError = messageObject.optString("error");
    serverErrorDescription = messageObject.optString("error_description");
    if (serverErrorDescription!=null && !serverErrorDescription.equals("")) {
        return serverErrorDescription;
    } else {
        return serverError;
    }
    //String serverStack = messageObject.getString("stack");
} catch (Exception e) {
    Log.e("Basemodel", "Error converting RetrofitError server JSON", e);
}

return "";
}

これにより、JSONでエンコードされたサービスから送信されたエラー情報が抽出されます。

0
neonDion

私は多くの答えをコンパイルし、より良い何かを達成するためにいくつかのコードを書きました:

{
    "errors": {
        "email": [
            "Email not valid.",
            "Unable to find the user [email protected]."
        ]
    }
}

私はすべてのアイテムを「電子メール」で受け取り、グアバジョイナーに含まれるそれらを表示します:

String json =  new String(((TypedByteArray)error.getResponse()
    .getBody()).getBytes());

Map<String, Object> map = new Gson().fromJson(
    json, new TypeToken<Map<String, Map<String, List<String>>>>() {}.getType());

try {
    List<String> errorsEmail = 
        (List<String>) ((Map)map.get("errors")).get("email");
    Toast.makeText(getApplicationContext(), Joiner.on("\n")
        .join(errorsEmail), Toast.LENGTH_SHORT).show();
} catch(Exception e){
    Log.e(Constants.TAG, e.getMessage());
}
0
Hugo Gresse

私は同じことをしていた。私の問題は、空のlong""としてサーバーから送られてきたStringフィールドでした。 RetrofitはNumberFormatExceptionを提供していました。Gsonは空の文字列をlongに変換していないように見えるためです(0Lなどにすることをお勧めします)。だから私は変更しなければなりませんでした:

long errorCode;

String errorCode;

前に言ったように、デバッグ時にはJSONメッセージにアクセスできませんでした。 RequestMakerページを使用してエラーを見つけた

http://requestmaker.com/

0
voghDev