Retrofit 2.0如何获得反序列化的错误响应.body

Pio*_*oho 103 java retrofit retrofit2

我正在使用Retrofit 2.0.0-beta1.

在测试中,我有一个替代方案,并期望错误HTTP 400

我想要retrofit.Response<MyError> response 但是response.body() == null

MyError没有反序列化 - 我只在这里看到它

response.errorBody().string()
Run Code Online (Sandbox Code Playgroud)

但它没有给我MyError作为对象

Sai*_*han 111

我目前使用非常简单的实现,不需要使用转换器或特殊类.我使用的代码如下:

public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
    DialogHelper.dismiss();

    if (response.isSuccessful()) {
        // Do your success stuff...
    } else {
        try {
            JSONObject jObjError = new JSONObject(response.errorBody().string());
            Toast.makeText(getContext(), jObjError.getJSONObject("error").getString("message"), Toast.LENGTH_LONG).show();
        } catch (Exception e) {
            Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您的解决方案未显示错误响应内容. (6认同)
  • jObjError.getString("error")对我有用 (3认同)
  • 检查我的编辑,不知道为什么我一开始就把它弄得这么不清楚。 (2认同)
  • 最后,一个有效的android问题的简单答案(大多数Android的答案是滑稽复杂的). (2认同)

JFr*_*man 30

在Retrofit 2.0 beta2中,这是我收到错误响应的方式:

  1. 同步

    try {
       Call<RegistrationResponse> call = backendServiceApi.register(data.in.account, data.in.password,
               data.in.email);
       Response<RegistrationResponse> response = call.execute();
       if (response != null && !response.isSuccess() && response.errorBody() != null) {
           Converter<ResponseBody, BasicResponse> errorConverter =
                   MyApplication.getRestClient().getRetrofitInstance().responseConverter(BasicResponse.class, new Annotation[0]);
           BasicResponse error = errorConverter.convert(response.errorBody());
           //DO ERROR HANDLING HERE
           return;
       }
       RegistrationResponse registrationResponse = response.body();
       //DO SUCCESS HANDLING HERE
    } catch (IOException e) {
       //DO NETWORK ERROR HANDLING HERE
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 异步

    Call<BasicResponse> call = service.loadRepo();
    call.enqueue(new Callback<BasicResponse>() {
        @Override
        public void onResponse(Response<BasicResponse> response, Retrofit retrofit) {
            if (response != null && !response.isSuccess() && response.errorBody() != null) {
                Converter<ResponseBody, BasicResponse> errorConverter =
                    retrofit.responseConverter(BasicResponse.class, new Annotation[0]);
                BasicResponse error = errorConverter.convert(response.errorBody());
                //DO ERROR HANDLING HERE
                return;
            }
            RegistrationResponse registrationResponse = response.body();
            //DO SUCCESS HANDLING HERE
        }
    
        @Override
        public void onFailure(Throwable t) {
            //DO NETWORK ERROR HANDLING HERE
        }
    });
    
    Run Code Online (Sandbox Code Playgroud)

更新Retrofit 2 beta3:

  1. 同步 - 没有改变
  2. 异步 - 从onResponse中删除了Retrofit参数

    Call<BasicResponse> call = service.loadRepo();
    call.enqueue(new Callback<BasicResponse>() {
        @Override
        public void onResponse(Response<BasicResponse> response) {
            if (response != null && !response.isSuccess() && response.errorBody() != null) {
                Converter<ResponseBody, BasicResponse> errorConverter =
                    MyApplication.getRestClient().getRetrofitInstance().responseConverter(BasicResponse.class, new Annotation[0]);
                BasicResponse error = errorConverter.convert(response.errorBody());
                //DO ERROR HANDLING HERE
                return;
            }
            RegistrationResponse registrationResponse = response.body();
            //DO SUCCESS HANDLING HERE
        }
    
        @Override
        public void onFailure(Throwable t) {
            //DO NETWORK ERROR HANDLING HERE
        }
    });
    
    Run Code Online (Sandbox Code Playgroud)

  • 你在BasicResponse中有什么? (4认同)
  • 只是一个基本的Jackson注释类,包含消息和错误代码.在任何情况下,您都可以在那里使用与您的服务器响应类型匹配的任何带注释的类.尝试使用[jsonschema2pojo](http://www.jsonschema2pojo.org/)生成符合您需求的一个. (2认同)

小智 28

我通过以下方式解决了

 if(!response.isSuccessful()){
       Gson gson = new Gson();
       MyErrorMessage message=gson.fromJson(response.errorBody().charStream(),MyErrorMessage.class);
       if(message.getCode()==ErrorCode.DUPLICATE_EMAIL_ID_CODE){
                  //DO Error Code specific handling                        
        }else{
                 //DO GENERAL Error Code Specific handling                               
        }
    }
Run Code Online (Sandbox Code Playgroud)

MyErrorMessage类:

  public class MyErrorMessage {
     private int code;
     private String message;

     public int getCode() {
        return code;
     }

     public void setCode(int code) {
        this.code = code;
     }

     public String getMessage() {
         return message;
     }

     public void setMessage(String message) {
        this.message = message;
     }
   }
Run Code Online (Sandbox Code Playgroud)

  • java.lang.IllegalStateException:预期为BEGIN_OBJECT,但在第1行第2列为STRING路径$ (2认同)

Sha*_*auf 25

ErrorResponse是您的自定义响应对象

科特林

val gson = Gson()
val type = object : TypeToken<ErrorResponse>() {}.type
var errorResponse: ErrorResponse? = gson.fromJson(response.errorBody()!!.charStream(), type)
Run Code Online (Sandbox Code Playgroud)

Java的

Gson gson = new Gson();
Type type = new TypeToken<ErrorResponse>() {}.getType();
ErrorResponse errorResponse = gson.fromJson(response.errorBody.charStream(),type);
Run Code Online (Sandbox Code Playgroud)

  • 你不应该强制解包选项:`gson.fromJson(response.errorBody()?.charStream(), type)` (3认同)
  • 你救了我的一天! (2认同)

Wha*_*rps 25

它实际上非常简单。

科特林:

val jsonObj = JSONObject(response.errorBody()!!.charStream().readText())
responseInterface.onFailure(jsonObj.getString("msg"))
Run Code Online (Sandbox Code Playgroud)

爪哇:

    if(response.errorBody()!=null){
    JSONObject jsonObj = new JSONObject(TextStreamsKt.readText(response.errorBody().charStream()));
        responseInterface.onFailure(jsonObj.getString("msg"));
    }else{
        responseInterface.onFailure("you might want to return a generic error message.");
    }
Run Code Online (Sandbox Code Playgroud)

改造测试:2.5.0。从 charStream 中读取文本,它会给你一个字符串,然后解析为 JSONObject。

阿迪欧斯。

  • java 上没有 `readText()` 扩展,如果您仍在使用 java,请使用 `TextStreamsKt.readText(response.errorBody().charStream())` (2认同)

Sre*_*noy 23

创建错误响应和用户 Gson 的模型以将响应转换为它。这将正常工作。

错误代码.java

public class APIError {
    private String message;

    public String getMessage() {
        return message;
    }
}
Run Code Online (Sandbox Code Playgroud)

MainActivity.java(内部请求 onResponse)

if (response.isSuccessful()) {
    // Do your success stuff...

} else {
    APIError message = new Gson().fromJson(response.errorBody().charStream(), APIError.class);
    Toast.makeText(MainActivity.this, "" + message.getMessage(), Toast.LENGTH_SHORT).show();
}
Run Code Online (Sandbox Code Playgroud)


Coo*_*ind 10

/sf/answers/1477239431/https://futurestud.io/tutorials/retrofit-2-simple-error-handling中,此变体显示为Retrofit 2.1.0.

call.enqueue(new Callback<MyResponse>() {
    @Override
    public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
        if (response.isSuccessful()) {
            ...
        } else {
            Converter<ResponseBody, MyError> converter
                    = MyApplication.getRetrofit().responseBodyConverter(
                    MyError.class, new Annotation[0]);
            MyError errorResponse = null;
            try {
                errorResponse = converter.convert(response.errorBody());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)


小智 7

我这样使用Retrofit 2.0-beta2进行异步调用:

@Override
public void onResponse(Response<RegistrationResponse> response, 
                       Retrofit retrofit) {
    if (response.isSuccess()) {
        // Do success handling here
    } else {
        try {
            MyError myError = (MyError)retrofit.responseConverter(
                    MyError.class, MyError.class.getAnnotations())
                .convert(response.errorBody());
            // Do error handling here
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Myr*_*lav 7

已经有很多有效的答案了。这只是一个用例的补充,当您需要多次使用相同的 Retrofit 响应时。以下两者都不能使用,因为您只能读取响应正文一次,因为它会在之后关闭,并且null当您尝试从同一响应对象读取时,您下次将会得到:

response()?.errorBody()?.charStream()?.readText()
response()?.errorBody()?.string()
Run Code Online (Sandbox Code Playgroud)

相反,您可以获得响应字符串的只读副本(而响应本身可以被传递并最终在稍后使用):

response()?.errorBody()?.source()?.buffer?.snapshot()?.utf8()
Run Code Online (Sandbox Code Playgroud)


Vin*_*ins 6

 @Override
 public void onResponse(Call<Void> call, retrofit2.Response<Void> response) {
            if (response.isSuccessful()) {

            //Do something if response is ok
            } else {

                JsonParser parser = new JsonParser();
                JsonElement mJson = null;
                try {
                    mJson = parser.parse(response.errorBody().string());
                    Gson gson = new Gson();
                    MyError errorResponse = gson.fromJson(mJson, MyError.class);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }

            }
Run Code Online (Sandbox Code Playgroud)


Ant*_*adz 6

这是使用Kotlin扩展的优雅解决方案:

data class ApiError(val code: Int, val message: String?) {
    companion object {
        val EMPTY_API_ERROR = ApiError(-1, null)
    }
}

fun Throwable.getApiError(): ApiError? {
    if (this is HttpException) {
        try {
            val errorJsonString = this.response()?.errorBody()?.string()
            return Gson().fromJson(errorJsonString, ApiError::class.java)
        } catch (exception: Exception) {
            // Ignore
        }
    }
    return EMPTY_API_ERROR
}
Run Code Online (Sandbox Code Playgroud)

和用法:

showError(retrofitThrowable.getApiError()?.message)


pav*_*vel 5

我面临同样的问题。我通过改造解决了它。让我展示这个...

如果您的错误 JSON 结构类似于

{
"error": {
    "status": "The email field is required."
}
}


My ErrorRespnce.java 

public class ErrorResponse {

   @SerializedName("error")
   @Expose
   private ErrorStatus error;

   public ErrorStatus getError() {
      return error;
   }

   public void setError(ErrorStatus error) {
      this.error = error;
   }
}
Run Code Online (Sandbox Code Playgroud)

这是我的错误状态类

public class ErrorStatus {

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

  public String getStatus() {
      return status;
  }

  public void setStatus(String status) {
      this.status = status;
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我们需要一个可以处理我们的 json 的类。

  public class ErrorUtils {

   public static ErrorResponse parseError (Response<?> response){
      Converter<ResponseBody , ErrorResponse> converter =          ApiClient.getClient().responseBodyConverter(ErrorResponse.class , new Annotation[0]);
    ErrorResponse errorResponse;
    try{
        errorResponse = converter.convert(response.errorBody());
    }catch (IOException e){
        return new ErrorResponse();
    }
    return errorResponse;
}
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以在改造 api 调用中检查我们的响应

private void registrationRequest(String name , String email , String password , String c_password){


    final Call<RegistrationResponce> registrationResponceCall = apiInterface.getRegistration(name , email , password , c_password);
    registrationResponceCall.enqueue(new Callback<RegistrationResponce>() {
        @Override
        public void onResponse(Call<RegistrationResponce> call, Response<RegistrationResponce> response) {



            if (response.code() == 200){


            }else if (response.code() == 401){


                ErrorResponse errorResponse = ErrorUtils.parseError(response);
                Toast.makeText(MainActivity.this, ""+errorResponse.getError().getStatus(), Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onFailure(Call<RegistrationResponce> call, Throwable t) {

        }
    });
}
Run Code Online (Sandbox Code Playgroud)

就是这样,现在你可以展示你的 Toast


Ars*_*ius 5

如果您使用Kotlin,则另一种解决方案可能只是为Response类创建扩展功能:

inline fun <reified T>Response<*>.parseErrJsonResponse(): T?
{
    val moshi = MyCustomMoshiBuilder().build()
    val parser = moshi.adapter(T::class.java)
    val response = errorBody()?.string()
    if(response != null)
        try {
            return parser.fromJson(response)
        } catch(e: JsonDataException) {
            e.printStackTrace()
        }
    return null
}
Run Code Online (Sandbox Code Playgroud)

用法

val myError = response.parseErrJsonResponse<MyErrorResponse>()
if(myError != null) {
   // handle your error logic here
   // ...
}
Run Code Online (Sandbox Code Playgroud)


Riy*_* PK 5

if(!response.isSuccessful()) {
    StringBuilder error = new StringBuilder();
    try {
        BufferedReader bufferedReader = null;
        if (response.errorBody() != null) {
            bufferedReader = new BufferedReader(new InputStreamReader(
                    response.errorBody().byteStream()));

            String eLine = null;
            while ((eLine = bufferedReader.readLine()) != null) {
                error.append(eLine);
            }
            bufferedReader.close();
        }

    } catch (Exception e) {
        error.append(e.getMessage());
    }

    Log.e("Error", error.toString());
}
Run Code Online (Sandbox Code Playgroud)


Pio*_*oho 0

通过以下方式解决了它:

Converter<MyError> converter = 
    (Converter<MyError>)JacksonConverterFactory.create().get(MyError.class);
MyError myError =  converter.fromBody(response.errorBody());
Run Code Online (Sandbox Code Playgroud)

  • MyError 类有什么? (4认同)