web-dev-qa-db-fra.com

Retrofit 2.0 - Comment obtenir le corps de réponse pour une erreur 400 Bad Request?

Ainsi, lorsque je fais un appel d'API POST sur mon serveur, j'obtiens une erreur 400 demande incorrecte avec une réponse JSON.

{
    "userMessage": "Blah",
    "internalMessage": "Bad Request blah blah",
    "errorCode": 1
}

Je l'appelle par 

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
    }
}

Cependant, le problème est qu’une fois que j’ai eu la réponse, onFailure () est appelé pour que // BB soit appelé. Ici, je n'ai aucun moyen d'accéder à la réponse JSON . Lorsque je consigne la demande et la réponse de l'API, la réponse JSON ne s'affiche pas du tout. Et Throwable est IOException. Cependant, étrangement, lorsque je fais le même appel sur Postman, la réponse JSON attendue est renvoyée avec un code d'erreur 400. 

Ma question est donc comment puis-je obtenir la réponse JSON quand je reçois une erreur 400 Bad Request? Dois-je ajouter quelque chose à okhttpclient?

Merci

20
user2062024

Vous pouvez le faire comme dans votre méthode onResponse, rappelez-vous que 400 est un statut de réponse et non une erreur:

if (response.code() == 400) {              
    Log.v("Error code 400",response.errorBody().string());
}

Et vous pouvez gérer n’importe quel code de réponse sauf 200-300 avec Gson comme:

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
        }        
}

Ajoutez ceci à votre build.gradle: compile 'com.google.code.gson:gson:2.7'

Si vous voulez créer la classe Pojo, accédez à Json Schema 2 Pojo et collez votre exemple de réponse Json. Sélectionnez le type de source Json et l'annotation Gson.

30
Yasin Kaçmaz

Vous pouvez essayer le code ci-dessous pour obtenir 400 réponses. Vous pouvez obtenir une réponse d'erreur de la méthode 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
    }
}
}

EDIT: Nom de méthode fixe de toString à string

7
Sathish Kumar VG

J'ai un problème similaire, mais le code existant était conforme à la chaîne RxJava 2. Voici ma solution:

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

transformer des réponses de type 400 en chaîne Rx est assez simple:

Call<Cat> request = catApi.getCat();
rxified(request, Cat.class).subscribe( (cat) -> println(cat) );
3
Lukas

Premier pas:

Créez votre classe POJO pour la réponse d'erreur. Dans mon cas, ApiError.Java

public class ApiError {

    @SerializedName("errorMessage")
    @Expose
    private String errorMessage;

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage= errorMessage;
    }
}

Deuxième étape:

Écrivez ci-dessous le code dans votre rappel d'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
     }
}

Ici, ApiClient.retrofit est votre instance de modification qui est statique.

2
Ekta Bhawsar
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();
        }
    }
}
2
Keshav Gera

Voici comment vous pouvez gérer le message de réponse Je gère l'erreur 500 que vous pouvez ajouter autant que vous le souhaitez.

                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;
                }
0
Shivam Mathur