改造 2 - 当响应状态为 422(不可处理实体)时,响应正文为空

Posted

技术标签:

【中文标题】改造 2 - 当响应状态为 422(不可处理实体)时,响应正文为空【英文标题】:Retrofit 2 - Response body null when response status is 422 (unprocessable entity) 【发布时间】:2016-03-12 11:54:36 【问题描述】:

我正在使用 Retrofit 在我的网络服务器中发出 POST 请求。

但是,当响应状态为422 (unprocessable entity) 时,我似乎无法获取响应正文。响应正文始终为null

我想知道我是否做错了什么,或者是否有解决方法。因为我在Postman的请求中使用了相同的json,它正常返回body。

这是方法:

@Headers("Content-Type: application/vnd.api+json")
@POST("my_endpoint")
Call<JsonObject> postEntry(@Header("Authorization") String authorization, @Body JsonObject json);

主体是一个 JsonObject,我没有像文档说的那样进行序列化。但我不认为这是问题所在。

【问题讨论】:

您的 api 是否在 422 错误中返回了一些正文?你是用安卓地图的吗? @DeividiCavarzan 是的,正如我在问题中提到的,当我使用 Postman 发出请求时,它会完美地返回正文。我在两个地方都使用相同的 json 对象。 @DeividiCavarzan 关于映射,是的,我做到了。它实际上使用response.body() == null 执行回调中的onResponse(Response&lt;JsonObject&gt; response, Retrofit retrofit) @Erick 你的请求没有完成,所以你面临这个问题.. 我建议在发送时拦截你的请求,使用 OkHttp 拦截器,看看你是否发送正确,与 Postman 的比较一下 【参考方案1】:

默认情况下,当您的服务器返回错误代码时,response.body() 始终为null。您正在寻找的是response.errorBody()。一种常见的方法是这样的:

    @Override
    public void onResponse(Response<JsonObject> response, Retrofit retrofit) 
        if (response.isSuccess()) 
            response.body(); // do something with this
         else 
            response.errorBody(); // do something with that
        
    

如果您需要更高级的内容,请查看 Interceptors 和 how to use them

【讨论】:

谢谢.. 但我的 errorBody() 也总是为空.. 我设法让它在没有改造的情况下工作。我奖励你赏金,因为它即将到期 泰。通过拦截器,您可以检查幕后发生的事情并查看原始请求和响应。无论如何,我很高兴你找到了办法:)【参考方案2】:

我遇到了同样的错误。我的 API 使用 POSTMAN 请求工作,但无法通过 android 改造调用工作。

起初我尝试使用@Field,但出现错误,但后来我尝试使用@Body,它成功了。

示例改造接口调用

@POST("api/v1/app/instance")
Call<InstanceResponse> updateTokenValue(
        @HeaderMap Map<String, String> headers,
        @Body String body); 

API调用代码为:

 Map<String, String> headerMap=new HashMap<>();
        headerMap.put("Accept", "application/json");
        headerMap.put("Content-Type", "application/json");
        headerMap.put("X-Authorization","access_token");

        Map<String, String> fields = new HashMap<>();
        fields.put("app_name", "video");
        fields.put("app_version", "2.0.0");
        fields.put("firebase_token", "token");
        fields.put("primary", "1");

        ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
        Call<InstanceResponse> call = apiInterface.updateTokenValue(
                headerMap,new Gson().toJson(fields));

【讨论】:

【参考方案3】:

那么在这种情况下,您必须转换响应。 看看这个link

上面的链接中已经提供了所有步骤。

对于 Kotlin 用户,这里是代码解决方案。

ErrorResponse.kt(这显然取决于您的错误响应)

import com.squareup.moshi.Json

data class ErrorResponse(

@Json(name="name")
val name: String? = null,

@Json(name="message")
val message: String? = null,

@Json(name="errors")
val errors: Errors? = null,

@Json(name="statusCode")
val statusCode: Int? = null
)

ApiFactory.kt(如果您需要完整代码,请告诉我)

fun parseError(response: Response<*>): ErrorResponse 
    val converter = ApiFactory.retrofit()
            .responseBodyConverter<ErrorResponse>(
                    ErrorResponse::class.java, arrayOfNulls<Annotation>(0)
            )

    val error: ErrorResponse

    try 
        error = converter.convert(response.errorBody()!!)!!
     catch (e: IOException) 
        e.printStackTrace()
        return ErrorResponse()
    

    return error

Presenter中(我使用MVP)

GlobalScope.launch(Dispatchers.Main) 
        try 
            val response = ApiFactory.apiService.LOGIN(username, password)
                    .await()
            val body = response.body()
            body?.let 
            // Handle success or any other stuff
                if (it.statusCode == 200) 
                    mView.onSuccess(it.data!!)
                
             ?:
            // This is the else part where your body is null
            // Here is how you use it.
            // Pass the response for error handling
            mView.showMessage(ApiFactory.parseError(response).message!!)
         catch (e: Exception) 
            e.printStackTrace()
        
    

这就是你的滚动方式! 就是这样!

【讨论】:

需要整个代码ApiFactory.kt

以上是关于改造 2 - 当响应状态为 422(不可处理实体)时,响应正文为空的主要内容,如果未能解决你的问题,请参考以下文章

如何反序列化 422 无法处理的实体错误模型并将错误绑定到 asp.net core razor pages 模型状态

前端react axios 发送post请求fastapi响应报错422 (Unprocessable Entity)

无法在 Microprofile Rest Client 中映射/获取 422 错误代码上的响应实体

Rails API 422 无法处理的实体:没有可用的验证密钥,heroku

在“422(无法处理的实体)”Laravel 7 中验证错误时出现错误

未处理拒绝SubmissionError:提交验证失败