【问题标题】:Getting JSON from RetrofitError object using Retrofit使用 Retrofit 从 RetrofitError 对象获取 JSON
【发布时间】:2014-01-04 12:56:54
【问题描述】:

我正在使用 Retrofit 库对我正在使用的服务进行 REST 调用。

如果我对我的服务进行 API 调用并出现故障,该服务会返回一些 JSON 以及标准 HTTP 错误内容。使用失败回调中包含的 RetrofitError 对象,我能够找到 HTTP 状态代码和其他一些内容,但是我无法检索服务发回的 JSON。

例如,假设我在尝试创建用户的地方调用 API。如果用户名已经存在,服务将返回 400 错误代码以及一些 JSON,如下所示:

{"error":"Username already in use"}

因为一个简单的 400 错误代码不够具体,我确实需要访问返回的 JSON。

有谁知道我如何获取这些 JSON 数据?我试过查看RetrofitError 对象中的每个字段,但在任何地方都找不到。我还需要做些什么吗?

【问题讨论】:

    标签: android retrofit


    【解决方案1】:

    您可以使用RetrofitError 对象的getBodyAs 方法。与其他 Retrofit 转换类似,它将响应转换为 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());
    

    【讨论】:

    • 您应该注意的一点是,如果 Converter 抛出 IOException/ConversionException,RetrofitError#getBodyAs(...) 可能会抛出 RuntimeException。当服务器开始返回意外的 XML 错误响应时,这导致我的应用程序崩溃。因此,您可能想编写自己的 getBodyAs 方法来捕获异常并优雅地处理这种情况。
    • 我尝试使用更新,但出现错误。 Unresolved reference: retrofit 所以我尝试了retrofit2,但它仍然不起作用
    【解决方案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);
    }
    

    【讨论】:

    • 这行得通。最容易做,尤其是如果您只是在调试东西。
    • 这可以很好地检索 HTTP 响应正文,但最好将其包装到 try { } catch 块中,因为它可能是 getResponse()/getBody 为空的情况,并且此代码将抛出 NullPointer 异常,例如非 HTTP 响应异常,例如:retrofit.RetrofitError: recvfrom failed: ECONNRESET (Connection reset by peer)
    【解决方案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】:

      使用getBodyAs 获取 JSON 对象的双线。

      JsonObject responseAsJson = (JsonObject) retrofitError.getBodyAs(JsonElement.class);
      
      String message = responseAsJson.get("error").getAsString(); //=> "Username already in use"
      

      确认在 Retrofit 1.x 中工作。不确定 Retrofit 2.x 需要进行哪些更改。

      【讨论】:

      • 在 Retrofit 1.9.0 上效果很好。感谢您提供简单的解决方案!
      【解决方案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
        

        这一切都来自this blog post(我写的)。

        【讨论】:

          【解决方案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 toto@toto.fr."
                    ]
                }
            }
            

            我将“电子邮件”中的所有项目与 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""。 Retrofit 给出了NumberFormatException,因为 Gson 似乎没有将空字符串转换为long(我建议将其设为 0L 或其他内容)。所以我不得不改变:

              long errorCode;
              

              String errorCode;
              

              如前所述,调试时我无法访问 JSON 消息。我终于使用 RequestMaker 页面找到了错误,也许它可以帮助其他人

              http://requestmaker.com/

              【讨论】:

                猜你喜欢
                • 2022-01-21
                • 1970-01-01
                • 1970-01-01
                • 2014-03-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多