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.gradle
:compile '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 客户端