Retrofit 2.0 - 如何获取 400 Bad Request 错误的响应正文?

Posted

技术标签:

【中文标题】Retrofit 2.0 - 如何获取 400 Bad Request 错误的响应正文?【英文标题】:Retrofit 2.0 - How to get response body for 400 Bad Request error? 【发布时间】:2016-11-10 08:26:32 【问题描述】:

因此,当我对我的服务器进行 POST API 调用时,我收到带有 JSON 响应的 400 Bad Request 错误。


    "userMessage": "Blah",
    "internalMessage": "Bad Request blah blah",
    "errorCode": 1

我叫它

Call.enqueue(new Callback<ResponseBody>() 
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 
        //AA
    

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) 
        //BB
    

但是问题是,一旦我得到响应,就会调用 onFailure() 以便调用 //BB。在这里,我无法访问 JSON 响应。 当我记录 api 请求和响应时,它根本不显示 JSON 响应。 Throwable t 是 IOException。然而,奇怪的是,当我在 Postman 上进行相同的调用时,它确实返回了预期的 JSON 响应和 400 错误代码。

所以我的问题是当我收到 400 Bad Request 错误时如何获得 json 响应?我应该向 okhttpclient 添加一些内容吗?

谢谢

【问题讨论】:

我认为这个答案会对你有所帮助。 retrofit 400 Bad Request 你解决了这个问题吗? 【参考方案1】:

您可以在 onResponse 方法中执行此操作,记住 400 是响应状态而不是错误:

if (response.code() == 400)               
    Log.v("Error code 400",response.errorBody().string());

您可以像这样使用Gson 处理任何响应代码除了 200-300

if (response.code() == 400) 
   Gson gson = new GsonBuilder().create();
   ErrorPojoClass mError=new ErrorPojoClass();
   try 
       mError= gson.fromJson(response.errorBody().string(),ErrorPojoClass.class);
       Toast.makeText(context, mError.getDescription(), Toast.LENGTH_LONG).show();
    catch (IOException e) 
       // handle failure to read error
           

将此添加到您的build.gradlecompile 'com.google.code.gson:gson:2.7'

如果您想创建 Pojo 类,请转到 Json Schema 2 Pojo 并粘贴您的示例 Json 响应。选择源类型 Json 和注释 Gson

【讨论】:

正如我所写,onResponse() 根本没有执行。而是执行 onFailure() ,因此我无法访问响应对象:( @user2062024 您是否尝试登录call.request().body().toString() 并查看有什么问题。通常它必须进入 onResponse ,但如果你提供更多代码,如果可能的话 Postman 截图,我会考虑。 @slanecek 我也在使用 Retrofit 并尝试了我的代码。试图用坏身体请求。它转到 onResponse。 @YasinKaçmaz 你是对的,我的错。 RC 400 在 Retrofit 1.x 中是一个错误 难怪我不能通过调用 response.body().string() 得到结果...感谢分享实际的方法是这样调用 response.errorBody().string( )【参考方案2】:

您可以尝试以下代码来获得 400 响应。您可以从 errorBody() 方法获得错误响应。

Call.enqueue(new Callback<ResponseBody>() 
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 
        //get success and error response here
 if (response.code() == 400) 
                if(!response.isSuccessful()) 
                    JSONObject jsonObject = null;
                    try 
                        jsonObject = new JSONObject(response.errorBody().string());
                        String userMessage = jsonObject.getString("userMessage");
                        String internalMessage = jsonObject.getString("internalMessage");
                        String errorCode = jsonObject.getString("errorCode");
                     catch (JSONException e) 
                        e.printStackTrace();
                    
                
            

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) 
        //get failure response here
    


编辑:将方法名称从toString 改为string

【讨论】:

【参考方案3】:
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 
    DialogHelper.dismiss();

    if (response.isSuccessful()) 
        // Success
     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();
        
    

【讨论】:

工作就像一个魅力! 是的,工作!太棒了!【参考方案4】:

第一步:

为错误响应创建您的 POJO 类。就我而言,ApiError.java

public class ApiError 

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

    public String getErrorMessage() 
        return errorMessage;
    

    public void setErrorMessage(String errorMessage) 
        this.errorMessage= errorMessage;
    

第二步:

在您的 api 回调中编写以下代码。

Call.enqueue(new Callback<RegistrationResponse>() 
     @Override
     public void onResponse(Call<RegistrationResponse> call, Response<RegistrationResponse> response) 
     
         if (response.isSuccessful()) 
             // do your code here
          else if (response.code() == 400) 
             Converter<ResponseBody, ApiError> converter =
                            ApiClient.retrofit.responseBodyConverter(ApiError.class, new Annotation[0]);

                    ApiError error;

                    try 
                        error = converter.convert(response.errorBody());
                        Log.e("error message", error.getErrorMessage());
                        Toast.makeText(context, error.getErrorMessage(), Toast.LENGTH_LONG).show();
                     catch (IOException e) 
                        e.printStackTrace();
                    
         
     

     @Override
     public void onFailure(Call<RegistrationResponse> call, Throwable t) 
         //do your failure handling code here
     

这里ApiClient.retrofit 是您的静态改造实例。

【讨论】:

【参考方案5】:

我遇到了类似的问题,但现有代码坚持使用 RxJava 2 链。 这是我的解决方案:

   public static <T> Observable<T> rxified(final Call<T> request, final Class<T> klazz) 
    return Observable.create(new ObservableOnSubscribe<T>() 

        AtomicBoolean justDisposed = new AtomicBoolean(false);

        @Override
        public void subscribe(final ObservableEmitter<T> emitter) throws Exception 

            emitter.setDisposable(new Disposable() 
                @Override
                public void dispose() 
                    request.cancel();
                    justDisposed.set(true);
                

                @Override
                public boolean isDisposed() 
                    return justDisposed.get();
                
            );

            if (!emitter.isDisposed())
                request.enqueue(new Callback<T>() 
                    @Override
                    public void onResponse(Call<T> call, retrofit2.Response<T> response) 
                        if (!emitter.isDisposed()) 
                            if (response.isSuccessful()) 
                                emitter.onNext(response.body());
                                emitter.onComplete();

                             else 
                                Gson gson = new Gson();
                                try 
                                    T errorResponse = gson.fromJson(response.errorBody().string(), klazz);
                                    emitter.onNext(errorResponse);
                                    emitter.onComplete();
                                 catch (IOException e) 
                                    emitter.onError(e);
                                
                            
                        
                    

                    @Override
                    public void onFailure(Call<T> call, Throwable t) 
                        if (!emitter.isDisposed()) emitter.onError(t);
                    
                );
        
    );

将类似 400 的响应转换为 rx 链非常简单:

Call<Cat> request = catApi.getCat();
rxified(request, Cat.class).subscribe( (cat) -> println(cat) );

【讨论】:

【参考方案6】:

这是最简单的解决方案,

如果要处理来自 onFailure 方法的响应:

@Override
public void onFailure(Call<T> call, Throwable t) 
    HttpException httpException = (HttpException) t;
    String errorBody = httpException.response().errorBody().string();
    // use Gson to parse json to your Error handling model class
    ErrorResponse errorResponse = Gson().fromJson(errorBody, ErrorResponse.class);

或者,如果你在 Kotlin 中使用 rxjava Observable,则从错误正文中处理它:

 error ->
    val httpException :HttpException = error as HttpException
    val errorBody: String = httpException.response().errorBody()!!.string()
    // use Gson to parse json to your Error handling model class
    val errorResponse: ErrorResponse = 
       Gson().fromJson(errorBody, ErrorResponse::class.java)

不要忘记正确处理 json 到类的转换(如果不确定,请使用 try-catch)。

【讨论】:

【参考方案7】:

用你的类对象处理 ErrorResponse

科特林

val errorResponse = Gson().fromJson(response.errorBody()!!.charStream(), ErrorResponse::class.java)

Java

ErrorResponse errorResponse = new Gson().fromJson(response.errorBody.charStream(),ErrorResponse.class)

【讨论】:

【参考方案8】:

简单地使用

 if (throwable is HttpException && (throwable!!.code() == 400 || throwable!!.code()==404))
                               var responseBody = throwable!!.response()?.errorBody()?.string()
                               val jsonObject = JSONObject(responseBody!!.trim())
                               var message = jsonObject.getString("message")
                               tvValMsg.set(message)
                             

【讨论】:

【参考方案9】:

这是处理响应消息的方式 我正在处理错误 500,您可以添加任意数量的内容

                switch (response.code()) 
                    case HttpURLConnection.HTTP_OK:
                        break;
                    case HttpURLConnection.HTTP_UNAUTHORIZED:
                        callback.onUnAuthentic();
                        break;
                    case HttpURLConnection.HTTP_INTERNAL_ERROR:
                        try 
                            String errorResponse = response.errorBody().string();
                            JSONObject object = new JSONObject(errorResponse);
                            String message = "Error";
                            if (object.has("Message"))
                                message = String.valueOf(object.get("Message"));
                            callback.onError(message);
                         catch (IOException e) 
                            e.printStackTrace();
                        
                        break;
                    case HttpURLConnection.HTTP_GATEWAY_TIMEOUT:
                    case HttpURLConnection.HTTP_CLIENT_TIMEOUT:
                    default:
                        callback.onNetworkError();
                        break;
                

【讨论】:

【参考方案10】:

如果你得到 400(Bad Request) 通过使用改造首先确保设置 API 的输入是 Only Model 类,如果没有,则将输入请求替换为模型类,然后检查你会得到成功响应。

@POST("api/users/CreateAccount")
Call<CreateAccount> createAccount(@Body CreateAccount model, @Header("Content-Type") String content_type);

【讨论】:

以上是关于Retrofit 2.0 - 如何获取 400 Bad Request 错误的响应正文?的主要内容,如果未能解决你的问题,请参考以下文章

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

如何使用 Retrofit 2.0 (Kotlin) 正确解析嵌套的 JSON 对象?

Retrofit2 POST 方法获取代码 400 但适用于 Restlet 客户端

无法在 Retrofit 2.0 android 中获取 json 字符串作为响应

如何使用拦截器在 Retrofit 2.0 中添加标头?

改造 2.0 如何打印完整的 json 响应?