How to handle error in Retrofit 2.0

2020-06-09 07:02发布

问题:

I want to handle error in Retrofit 2.0

Got e.g. code=404 and body=null, but errorBody() contains data in ErrorModel (Boolean status and String info).

This is errorBody().content: [text=\n{"status":false,"info":"Provided email doesn't exist."}].

How can I get this data?

Thank for helping me!

This is my code for Retrofit request:

ResetPasswordApi.Factory.getInstance().resetPassword(loginEditText.getText().toString())
    .enqueue(new Callback<StatusInfoModel>() {
        @Override
        public void onResponse(Call<StatusInfoModel> call, Response<StatusInfoModel> response) {
            if (response.isSuccessful()) {
                showToast(getApplicationContext(), getString(R.string.new_password_sent));
            } else {
                showToast(getApplicationContext(), getString(R.string.email_not_exist));
            }
        }

        @Override
        public void onFailure(Call<StatusInfoModel> call, Throwable t) {
            showToast(getApplicationContext(), "Something went wrong...");
        }
    });

回答1:

If you want to get data when error response comes (typically a response code except 200) you can do it like that in your onResponse() method:

if (response.code() == 404) {
    Gson gson = new GsonBuilder().create();
    YourErrorPojo pojo = new YourErrorPojo();
    try {
         pojo = gson.fromJson(response.errorBody().string(), YourErrorPojo.class);
         Toast.makeText(context, pojo.getInfo(), Toast.LENGTH_LONG).show();
    } catch (IOException e) { // handle failure at error parse }
}

When generating YourErrorPojo.class do following steps :

  1. Go to Json Schema 2 Pojo

  2. Paste your example Json, and select source type Json , annotation Gson

  3. Your example Json is : {"status":false,"info":"Provided email doesn't exist."}

  4. Click Preview and it will generate your Pojo class for you.

Add this to your build.gradle : compile 'com.google.code.gson:gson:2.7'

I used Gson in this solution but you can get your Json string using: response.errorBody().string()



回答2:

Retrofit doesn't see 404 as a failure, so it will enter the onSuccess.

response.isSuccessful() is true if the response code is in the range of 200-300, so it will enter the else there.

if (response.isSuccessful()) {
    showToast(getApplicationContext(), getString(R.string.new_password_sent));
} else {
    // A 404 will go here

    showToast(getApplicationContext(), getString(R.string.email_not_exist));
}

However since your response was not successful, you do not get the response body with .body(), but with errorBody(), errorBody will filled when the request was a success, but response.isSuccessful() returns false (so in case of a status code that is not 200-300).



回答3:

I'm using this library Retrobomb, you don't have to serialize at that level. it's easy to use and customize. It supports annotation for each error type or error code. If you prefer you can unwrap all errors and handle by your self.

@ErrorMapping(code = 401, errorType = Unauthorized.class)
@PATCH("/v1/widgets/{id}")
  Single<Widget> updateWidget(@Path("id") String id, @Body Widget widget);


回答4:

If you want to get data when error response comes (typically a response code except 200) you can do it like that in your onResponse() method:

override fun onResponse(call: Call<LoginData>?, response: Response<LoginData>?) {
    if (response != null) {
        if (response.code() == 200 && response.body() != null) {
            val loginData = response.body()
            if (loginData != null) {
                //Handle success case...
            }
        } else if (response.code() == 401) {
            val converter = ApiClient.getClient()?.responseBodyConverter<ErrorResponseData>(
                ErrorResponseData::class.java,
                arrayOfNulls<Annotation>(0))
            var errorResponse: ErrorResponseData? = null
            errorResponse = converter?.convert(response.errorBody())
            if (errorResponse != null) {
                //Handle Error case..
            }
        }
    }
}