Retrofit 2.0 - Как получить тело ответа за 400 ошибок Bad Request?
Поэтому, когда я вызываю вызов API POST на мой сервер, я получаю ошибку 400 Bad Request с ответом JSON.
{
"userMessage": "Blah",
"internalMessage": "Bad Request blah blah",
"errorCode": 1
}
Я называю это
Call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//AA
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
//BB
}
}
Однако проблема заключается в том, что как только я получаю ответ, onFailure() вызывается так, что вызывается //BB. Здесь у меня нет доступа к ответу JSON.
Когда я регистрирую запрос и ответ api, он вообще не показывает ответ JSON. И Throwable t - это исключение IOException. Однако, как ни странно, когда я делаю тот же вызов в Postman, он возвращает ожидаемый ответ JSON с 400 кодом ошибки.
Итак, мой вопрос: как я могу получить ответ json, когда я получаю ошибку 400 Bad Request? Должен ли я добавить что-то к okhttpclient?
Спасибо
Ответы
Ответ 1
Вы можете сделать это как в своем методе onResponse
, помните, что 400 - это статус ответа, а не ошибка:
if (response.code() == 400) {
Log.v("Error code 400",response.errorBody().string());
}
И вы можете обрабатывать любой код ответа кроме 200-300 с помощью Gson
, например:
if (response.code() == 400) {
Gson gson = new GsonBuilder().create();
ErrorPojoClass mError=new ErrorPojoClass();
try {
mError= gson.fromJson(response.errorBody().string(),ErrorPojoClass .class);
Toast.makeText(getApplicationContext(), mError.getErrorDescription(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
// handle failure to read error
}
}
Добавьте это в свой build.gradle
: compile 'com.google.code.gson:gson:2.7'
Если вы хотите создать класс Pojo
, перейдите в Json Schema 2 Pojo и вставьте свой пример ответа Json
. Выберите тип источника Json и аннотация Gson.
Ответ 2
Вы можете попробовать следующий код, чтобы получить 400 ответов. Вы можете получить ответ об ошибке из метода errorBody().
Call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//get success and error response here
if (response.code() == 400) {
if(!response.isSuccessful()) {
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(response.errorBody().string());
String userMessage = jsonObject.getString("userMessage");
String internalMessage = jsonObject.getString("internalMessage");
String errorCode = jsonObject.getString("errorCode");
} catch (JSONException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
//get failure response here
}
}
}
РЕДАКТИРОВАТЬ: Исправлено имя метода из toString
в string
Ответ 3
У меня была аналогичная проблема, но существующий код придерживался сети RxJava 2.
Здесь мое решение:
public static <T> Observable<T> rxified(final Call<T> request, final Class<T> klazz) {
return Observable.create(new ObservableOnSubscribe<T>() {
AtomicBoolean justDisposed = new AtomicBoolean(false);
@Override
public void subscribe(final ObservableEmitter<T> emitter) throws Exception {
emitter.setDisposable(new Disposable() {
@Override
public void dispose() {
request.cancel();
justDisposed.set(true);
}
@Override
public boolean isDisposed() {
return justDisposed.get();
}
});
if (!emitter.isDisposed())
request.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, retrofit2.Response<T> response) {
if (!emitter.isDisposed()) {
if (response.isSuccessful()) {
emitter.onNext(response.body());
emitter.onComplete();
} else {
Gson gson = new Gson();
try {
T errorResponse = gson.fromJson(response.errorBody().string(), klazz);
emitter.onNext(errorResponse);
emitter.onComplete();
} catch (IOException e) {
emitter.onError(e);
}
}
}
}
@Override
public void onFailure(Call<T> call, Throwable t) {
if (!emitter.isDisposed()) emitter.onError(t);
}
});
}
});
}
Преобразование 400-подобных ответов в цепочку rx довольно просто:
Call<Cat> request = catApi.getCat();
rxified(request, Cat.class).subscribe( (cat) -> println(cat) );
Ответ 4
Первый шаг:
Создайте свой класс POJO для ответа об ошибке. В моем случае ApiError.java
public class ApiError {
@SerializedName("errorMessage")
@Expose
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage= errorMessage;
}
}
Второй шаг:
Напишите ниже код в вашем обратном вызове API.
Call.enqueue(new Callback<RegistrationResponse>() {
@Override
public void onResponse(Call<RegistrationResponse> call, Response<RegistrationResponse> response)
{
if (response.isSuccessful()) {
// do your code here
} else if (response.code() == 400) {
Converter<ResponseBody, ApiError> converter =
ApiClient.retrofit.responseBodyConverter(ApiError.class, new Annotation[0]);
ApiError error;
try {
error = converter.convert(response.errorBody());
Log.e("error message", error.getErrorMessage());
Toast.makeText(context, error.getErrorMessage(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<RegistrationResponse> call, Throwable t) {
//do your failure handling code here
}
}
Здесь ApiClient.retrofit
- это ваш экземпляр модернизации, который является статическим.
Ответ 5
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
DialogHelper.dismiss();
if (response.isSuccessful()) {
// Success
} else {
try {
JSONObject jObjError = new JSONObject(response.errorBody().string());
Toast.makeText(getContext(), jObjError.getString("message"), Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
Ответ 6
Вот как вы можете обрабатывать ответное сообщение
Я обрабатываю ошибку 500, вы можете добавить столько, сколько хотите.
switch (response.code()) {
case HttpURLConnection.HTTP_OK:
break;
case HttpURLConnection.HTTP_UNAUTHORIZED:
callback.onUnAuthentic();
break;
case HttpURLConnection.HTTP_INTERNAL_ERROR:
try {
String errorResponse = response.errorBody().string();
JSONObject object = new JSONObject(errorResponse);
String message = "Error";
if (object.has("Message"))
message = String.valueOf(object.get("Message"));
callback.onError(message);
} catch (IOException e) {
e.printStackTrace();
}
break;
case HttpURLConnection.HTTP_GATEWAY_TIMEOUT:
case HttpURLConnection.HTTP_CLIENT_TIMEOUT:
default:
callback.onNetworkError();
break;
}