Подтвердить что ты не робот

Получение JSON из объекта RetrofitError с использованием Retrofit

Я использую библиотеку Retrofit для выполнения вызовов REST для службы, которую я использую.

Если я вызываю вызов API моей службе и имею сбой, служба возвращает бит JSON вместе со стандартным сообщением об ошибке HTTP. Используя объект RetrofitError, включенный в обратный вызов отказа, я могу найти код состояния HTTP и несколько других вещей, однако я не могу получить JSON, который служба отправляет обратно.

Например, скажем, я звоню в API, где я пытаюсь создать пользователя. Если имя пользователя уже существует, служба вернет код ошибки 400 вместе с некоторым JSON следующим образом:

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

Поскольку простой код ошибки 400 не является достаточно конкретным, мне действительно нужен доступ к возвращенному JSON.

Кто-нибудь знает, как я могу получить данные JSON? Я пробовал смотреть на каждое поле в объекте RetrofitError и не могу найти его нигде. Есть ли что-то дополнительное, что мне нужно делать?

4b9b3361

Ответ 1

Вы можете использовать метод getBodyAs объекта RetrofitError. Он преобразует ответ на объект 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());

Ответ 2

Попробуйте этот код

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

с Дооснащение 2.0

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

Ответ 3

@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);
    }

Ответ 4

JsonElement jsonElement = (JsonElement) retrofitError.getBodyAs(JsonElement.class);

Ответ 5

Используя это, вы можете получить тело ошибки

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

Ответ 6

Более простой способ сделать это - создать класс, который может выполнить синтаксический анализ/преобразование для вас, тот, который вы можете вызывать в любое время и в любом месте.

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

Это все из это сообщение в блоге (которое я написал).

Ответ 7

Итак, после небольшой охоты я нашел ответ.

Здесь мой отказ:

@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.

Ответ 8

Я компилирую много ответов и написал код для достижения чего-то более приятного:

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

Я беру все элементы в "email" и отображаю их в конкатенации с Guava Joiner:

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());
}

Ответ 9

У меня было то же самое. Моя проблема была в поле long, которое поступало с сервера как пустой String "". "Дооснащение" давало NumberFormatException, потому что похоже, что Gson не конвертирует пустую строку в long (я бы предложил сделать это 0L или что-то еще). Поэтому мне пришлось изменить:

long errorCode;

к

String errorCode;

Как уже было сказано, у меня не было доступа к сообщению JSON при отладке. Я, наконец, нашел ошибку, используя страницу RequestMaker, возможно, она помогает кому-то еще

http://requestmaker.com/