Retrofitライブラリを使用して、REST使用しているサービスへの呼び出しを行います。
サービスに対してAPI呼び出しを行って失敗した場合、サービスは標準のHTTPエラーと一緒に少しのJSONを返します。失敗コールバックに含まれるRetrofitError
オブジェクトを使用すると、HTTPステータスコードと他のいくつかのものを見つけることができますが、サービスが送り返すJSONを取得することはできません。
たとえば、ユーザーを作成しようとしているAPIを呼び出したとします。ユーザー名が既に存在する場合、サービスは次のようなJSONとともに400エラーコードを返します。
{"error":"Username already in use"}
単純な400エラーコードでは十分に具体的ではないため、返されるJSONにアクセスする必要があります。
誰もがこのJSONデータをどのように取得できるか知っていますか? RetrofitError
オブジェクトのすべてのフィールドを調べてみましたが、どこにも見つかりません。他に何かする必要があることはありますか?
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());
このコードを試してください
@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);
}
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に必要な変更はわかりません。
@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);
}
これを使用すると、エラー本文を取得できます
if (response != null && response.errorBody() != null) {
JSONObject jsonObject = new JSONObject(response.errorBody().string());
String error = jsonObject.getString("error");
}
これを行うための非常にすてきな方法は、いつでもどこでも呼び出すことができる、あなたのために解析/変換を行うことができるクラスを作成することです。
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
これはすべて このブログ投稿 (私が書いた)からです。
それで、もう少し狩りをして、答えを見つけました。
ここに私の失敗のコールバックがあります:
@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でエンコードされたサービスから送信されたエラー情報が抽出されます。
私は多くの答えをコンパイルし、より良い何かを達成するためにいくつかのコードを書きました:
{
"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());
}
私は同じことをしていた。私の問題は、空のlong
""
としてサーバーから送られてきたString
フィールドでした。 RetrofitはNumberFormatException
を提供していました。Gsonは空の文字列をlong
に変換していないように見えるためです(0Lなどにすることをお勧めします)。だから私は変更しなければなりませんでした:
long errorCode;
に
String errorCode;
前に言ったように、デバッグ時にはJSONメッセージにアクセスできませんでした。 RequestMakerページを使用してエラーを見つけた