【问题标题】:How to handle error response with Retrofit 2?如何使用 Retrofit 2 处理错误响应?
【发布时间】:2017-04-10 11:39:36
【问题描述】:

如何使用同步请求处理 Retrofit 2 的错误响应?

我需要在正常情况下返回宠物数组的过程响应,如果请求的参数错误,则返回错误 json 对象。这两种情况如何处理?

我正在尝试使用this 教程,但主要问题是将正常和错误 json 映射到对象。

我的正常反应示例:

[ {
    "type" : "cat",
    "color": "black"
}, 
{
    "type" : "cat",
    "color": "white"
} ]

错误响应示例:

{"error" = "-1", error_description = "Low version"}

我得到了什么:

    Call<List<Pet>> call = getApiService().getPet(1);
    Response<List<Pet>> response;
    List<Pet> result = null;

    try {
        response = call.execute(); //line with exception "Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path"
        if(!response.isSuccessful()){
            Error error = parseError(response);
            Log.d("error message", error.getErrorDescription());
        }
        if (response.code() == 200) {
            result = response.body();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

【问题讨论】:

  • 你的代码到底有什么问题?

标签: android json retrofit2


【解决方案1】:

Retrofit 2 处理“成功”请求的概念与 Retrofit 1 不同。在 Retrofit 2 中,所有可以执行(发送到 API)并且您收到响应的请求都被视为“成功” .这意味着,对于这些请求,会触发 onResponse 回调,您需要手动检查请求是实际成功(状态 200-299)还是错误(状态 400-599)。

如果请求成功完成,我们可以使用响应对象并做任何我们想做的事情。如果错误确实失败(请记住,状态 400-599),我们希望向用户显示有关该问题的适当信息。

更多详情请参考link

【讨论】:

  • 我明白,但主要问题是处理两个json对象:宠物数组(正常情况下)和错误响应(如果请求有错误的参数)。
  • @AndrewEvtukhov 你是如何通过改造 2 解决这个问题的?
【解决方案2】:

经过多种解决方案。我发布它以供更动态的使用。希望对大家有所帮助。

我的错误响应

{
"severity": 0,
"errorMessage": "Incorrect Credentials (Login ID or Passowrd)"
}

下面是照常调用方法

private void makeLoginCall() {
    loginCall = RetrofitSingleton.getAPI().sendLogin(loginjsonObject);
    loginCall.enqueue(new Callback<Login>() {
        @Override
        public void onResponse(Call<Login> call, Response<Login> response) {
            if (response != null && response.code() == 200){
                //Success handling
            }
            else if (!response.isSuccessful()){
                mServerResponseCode = response.code();
                Util.Logd("In catch of login else " + response.message());
                /*
                * Below line send respnse to Util class which return a specific error string
                * this error string is then sent back to main activity(Class responsible for fundtionality)
                * */

                mServerMessage = Util.parseError(response) ;
                mLoginWebMutableData.postValue(null);
                loginCall = null;
            }
        }

        @Override
        public void onFailure(Call<Login> call, Throwable t) {
            Util.Logd("In catch of login " + t.getMessage());
            mLoginWebMutableData.postValue(null);
            mServerMessage = t.getMessage();
            loginCall = null;
        }
    });
}

下面是处理解析的util类

public static String parseError(Response<?> response){
    String errorMsg = null;
    try {
        JSONObject jObjError = new JSONObject(response.errorBody().string());
        errorMsg = jObjError.getString("errorMessage");
        Util.Logd(jObjError.getString("errorMessage"));
        return errorMsg ;
    } catch (Exception e) {
        Util.Logd(e.getMessage());
    }
    return errorMsg;
}

在 viewModel 观察者下方

private void observeLogin() {
    loginViewModel.getmLoginVModelMutableData().observe(this, login -> {
        if (loginViewModel.getSerResponseCode() != null) {
            if (loginViewModel.getSerResponseCode().equals(Constants.OK)) {
                if (login != null) {
                    //Your logic here
                }
            }
           //getting parsed response message from client to handling class
            else {
                Util.stopProgress(this);
                Snackbar snackbar = Snackbar.make(view, loginViewModel.getmServerVModelMessage(), BaseTransientBottomBar.LENGTH_INDEFINITE).setAction(android.R.string.ok, v -> { });
                snackbar.show();
            }
        } else {
            Util.stopProgress(this);
            Snackbar snackbar = Snackbar.make(view, "Some Unknown Error occured", BaseTransientBottomBar.LENGTH_INDEFINITE).setAction(android.R.string.ok, v -> { });
            snackbar.show();
        }
    });
}

【讨论】:

    【解决方案3】:

    我认为您应该创建一个通用响应类(比如GenericResponse),由特定响应类(比如PetResponse)扩展。在第一个中,您包含通用属性(errorerror_description),在后者中,您输入您的特定响应数据(List&lt;Pet&gt;)。

    在你的情况下,我会选择这样的:

    class GenericResponse {
       int error;
       String error_description;
    } 
    
    class PetResponse extends GenericResponse {
       List<Pet> data;
    }
    

    因此,您成功的响应正文应如下所示:

    {
       "data": [ {
            "type" : "cat",       
            "color": "black"
          }, 
          {
            "type" : "cat",
            "color": "white"
          } ]
    }
    

    您的错误响应正文应如下所示:

    { "error" = "-1", error_description = "Low version"}
    

    最后,从 API 调用返回的响应对象应该是:

       Response<PetResponse> response;
    

    【讨论】:

      【解决方案4】:

      像这样将你所有的电话都封装在retrofit2.Response 中:

      @POST("user/login")
      suspend fun login(@Body form: Login): Response<LoginResponse>
      

      一个非常简单的改造 2 错误处理程序:

      fun <T> retrofitErrorHandler(res: Response<T>): T {
          if (res.isSuccessful) {
              return res.body()!!
          } else {
              val errMsg = res.errorBody()?.string()?.let {
                  JSONObject(it).getString("error") // or whatever your message is
              } ?: run {
                  res.code().toString()
              }
      
              throw Exception(errMsg)
          }
      }
      

      然后像这样使用它们:

      try {
        createdReport = retrofitErrorHandler(api...)
      } catch (e: Exception) {
        toastException(ctx = ctx, error = e)
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-18
        • 2023-03-15
        • 1970-01-01
        • 2017-01-01
        • 2019-03-13
        • 2016-07-02
        • 2020-03-13
        • 2017-11-24
        相关资源
        最近更新 更多