Получение JSON из объекта RetrofitError с использованием Retrofit
Я использую библиотеку Retrofit для выполнения вызовов REST для службы, которую я использую.
Если я вызываю вызов API моей службе и имею сбой, служба возвращает бит JSON вместе со стандартным сообщением об ошибке HTTP. Используя объект RetrofitError
, включенный в обратный вызов отказа, я могу найти код состояния HTTP и несколько других вещей, однако я не могу получить JSON, который служба отправляет обратно.
Например, скажем, я звоню в API, где я пытаюсь создать пользователя. Если имя пользователя уже существует, служба вернет код ошибки 400 вместе с некоторым JSON следующим образом:
{"error":"Username already in use"}
Поскольку простой код ошибки 400 не является достаточно конкретным, мне действительно нужен доступ к возвращенному JSON.
Кто-нибудь знает, как я могу получить данные JSON? Я пробовал смотреть на каждое поле в объекте RetrofitError
и не могу найти его нигде. Есть ли что-то дополнительное, что мне нужно делать?
Ответы
Ответ 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/