使用Retrofit从RetrofitError对象获取JSON

时间:2013-12-16 23:00:11

标签: android retrofit

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

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

例如,让我说我打算调用我正在尝试创建用户的API。如果用户名已经存在,该服务将返回400错误代码以及一些类似的JSON:

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

因为简单的400错误代码不够具体,所以我真的需要访问返回的JSON。

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

8 个答案:

答案 0 :(得分:103)

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

答案 1 :(得分:20)

试试此代码

@Override
public void failure(RetrofitError error) {
    String json =  new String(((TypedByteArray)error.getResponse().getBody()).getBytes());
    Log.v("failure", json.toString());
}

Retrofit 2.0

@Override
public void onFailure(Call<Example> call, Throwable t) {
    String message = t.getMessage();
    Log.d("failure", message);
}

答案 2 :(得分:5)

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

答案 3 :(得分:5)

带有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需要进行哪些更改。

答案 4 :(得分:1)

使用此功能可以获取错误正文

  if (response != null && response.errorBody() != null) {
    JSONObject jsonObject = new JSONObject(response.errorBody().string());
    String error =  jsonObject.getString("error");
  }

答案 5 :(得分:1)

更简洁的方法是创建一个可以为您进行解析/转换的类,您可以随时随地调用它。

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(我写的)。

答案 6 :(得分:0)

经过多一点狩猎后,我找到了答案。

这是我的失败回调:

@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编码的服务发送的错误信息。

答案 7 :(得分:0)

我编译了许多答案并编写了一些代码来实现更好的功能:

{
    "errors": {
        "email": [
            "Email not valid.",
            "Unable to find the user toto@toto.fr."
        ]
    }
}

我把所有项目都放在&#39; email&#39;并用番石榴木匠展示它们:

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