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

我正在使用Retrofit 2.0.0-beta1

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

我想有retrofit.Response<MyError> responseresponse.body() == null

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

 response.errorBody().string() 

但它不会给我MyError作为对象

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

 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.getString("message"), Toast.LENGTH_LONG).show(); } catch (Exception e) { Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show(); } } } 

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

更新2 beta3更新:

  1. 同步 – 没有改变
  2. Asynchronous – Retrofit参数已从onResponse中删除

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

我解决了它:

  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 } } 

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

我这样做了使用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(); } } } 

https://stackoverflow.com/a/21103420/2914140和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(); } } } 
  @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(); } } 

这样,如果只注入从Retrofit创建的服务,则不需要Retrofit实例。

 public class ErrorUtils { public static APIError parseError(Context context, Response<?> response) { APIError error = new APIError(); try { Gson gson = new Gson(); error = gson.fromJson(response.errorBody().charStream(), APIError.class); } catch (Exception e) { Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show(); } if (TextUtils.isEmpty(error.getErrorMessage())) { error.setError(response.raw().message()); } return error; } } 

像这样使用它:

 if (response.isSuccessful()) { ... } else { String msg = ErrorUtils.parseError(fragment.getActivity(), response).getError(); // would be from your error class Snackbar.make(someview, msg, Snackbar.LENGTH_LONG).show(); } } 

当你使用OkHttp和Retrofit时,这似乎是问题,所以要么删除OkHttp,要么使用下面的代码来获取错误主体:

 if (!response.isSuccessful()) { InputStream i = response.errorBody().byteStream(); BufferedReader r = new BufferedReader(new InputStreamReader(i)); StringBuilder errorResult = new StringBuilder(); String line; try { while ((line = r.readLine()) != null) { errorResult.append(line).append('\n'); } } catch (IOException e) { e.printStackTrace(); } } 

在Kotlin:

 val call = APIClient.getInstance().signIn(AuthRequestWrapper(AuthRequest("1234567890z", "12341234", "nonce"))) call.enqueue(object : Callback<AuthResponse> { override fun onResponse(call: Call<AuthResponse>, response: Response<AuthResponse>) { if (response.isSuccessful) { } else { val a = object : Annotation{} val errorConverter = RentalGeekClient.getRetrofitInstance().responseBodyConverter<AuthFailureResponse>(AuthFailureResponse::class.java, arrayOf(a)) val authFailureResponse = errorConverter.convert(response.errorBody()) } } override fun onFailure(call: Call<AuthResponse>, t: Throwable) { } }) 

如何一些广义的解决方案,我认为这样的事情可能工作:

 abstract class TestCallback<RESPONSE, ERROR extends Throwable> implements Callback<RESPONSE> { Class<ERROR> errorClass; Retrofit retrofit; TestCallback(Retrofit retrofit, Class<ERROR> errorClass) { this.retrofit = retrofit; this.errorClass = errorClass; } abstract void onSuccess(Call<RESPONSE> call, RESPONSE response); @Override public void onResponse(Call<RESPONSE> call, Response<RESPONSE> response) { if (response.isSuccessful()) { onSuccess(call, response.body()); return; } if (response.errorBody() != null) { Converter<ResponseBody, ERROR> converter = retrofit.responseBodyConverter(errorClass, new Annotation[0]); ERROR error; try { error = converter.convert(response.errorBody()); onFailure(call, error); } catch (IOException e) { // Conversion error. Add some meaningful message or return a custom error. onFailure(call, new Throwable()); } } else { // Unknown HTTP error (errorBody == null). Add some meaningful message or return a custom error. onFailure(call, new Throwable()); } } } 

然后我们可以用下面的方式使用这个自定义Callback<>

 Call<User> call = retrofit.create(UsersApi.class).signUp(email, password); call.enqueue(new TestCallback<User, TestError>(retrofit, TestError.class) { @Override public void onFailure(Call<User> call, Throwable t) { if (t instanceof TestError) { } else { } } @Override void onSuccess(Call<User> call, User response) { // No need to check for isSuccessful() + no need to // duplicate the same code for all of your handlers. } }); 

解决它:

 Converter<MyError> converter = (Converter<MyError>)JacksonConverterFactory.create().get(MyError.class); MyError myError = converter.fromBody(response.errorBody()); 
 try{ ResponseBody response = ((HttpException) t).response().errorBody(); JSONObject json = new JSONObject( new String(response.bytes()) ); errMsg = json.getString("message"); }catch(JSONException e){ return t.getMessage(); } catch(IOException e){ return t.getMessage(); }