【问题标题】:Retrofit2 Deserialize response body even if response is not 200Retrofit2 反序列化响应体,即使响应不是 200
【发布时间】:2017-07-04 13:12:38
【问题描述】:

即使响应不成功,我也希望能够反序列化对同一 Java 对象的网络响应。目前,当我收到类似 403 的错误响应时,响应正文为空,我应该使用 response.errorBody() 方法读取已发回的任何内容,这没关系。但是我想避免在改造回调中有很多代码只是为了反序列化errorBody。相反,我想要一个拦截器,将 errorBody 的内容设置为正文。

这样做的原因是我有一个响应对象,该对象包含错误和非错误响应的字段,并且根据响应的状态,某些字段应为空,例如

错误响应 JSON

{
"locked":true,
"remaining_attempts": 2
}

成功响应 JSON

{
"name":"kev"
"token":"abcdefghijklmnopq"
}

我创建了一个 Java 对象来捕获这两种情况:

class LoginResponse{
    @Expose
    private String name;
    @Expose
    private String token;
    @Expose
    private Boolean locked;
    @Expose
    private Integer remaining_attempts;
}

有没有办法在拦截器中做到这一点?

【问题讨论】:

  • 我遇到了类似的问题,经过搜索我发现解决方案是编写一个自定义的ConverterFactory 来扩展默认的改造转换器。
  • @MohamedIbrahim 有链接吗?
  • 我将在@kev 发布我的答案并提供更多信息

标签: android retrofit2


【解决方案1】:

Retrofit 通过将序列化部分委托给转换器来完成序列化部分,您可以使用 builder.addConverterFactory(GsonConverterFactory.create()) 将特定序列化部分添加到构建器中 而且已经有很多写的Retrofit Converters了,大部分都可以找到here

所以如果你想控制这个反序列化过程,你可以编写你的自定义转换器,像这样

public class UnwrapConverterFactory extends Converter.Factory {

    private GsonConverterFactory factory;

    public UnwrapConverterFactory(GsonConverterFactory factory) {
        this.factory = factory;
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(final Type type,
            Annotation[] annotations, Retrofit retrofit) {
        // e.g. WrappedResponse<Person>
        Type wrappedType = new ParameterizedType() {
            @Override
            public Type[] getActualTypeArguments() {
                // -> WrappedResponse<type>
                return new Type[] {type};
            }

            @Override
            public Type getOwnerType() {
                return null;
            }

            @Override
            public Type getRawType() {
                return WrappedResponse.class;
            }
        };
        Converter<ResponseBody, ?> gsonConverter = factory
                .responseBodyConverter(wrappedType, annotations, retrofit);
        return new WrappedResponseBodyConverter(gsonConverter);
    }
}

然后你再次使用addConverterFactory() 告诉Retrofit 新转换器。 我应该提一下,您可以在 Retrofit 中使用多个转换器,这很棒,它只需按顺序检查转换器,直到找到合适的转换器。

资源:writing custom Retrofit converterusing multiple converters

【讨论】:

    【解决方案2】:

    您可以直接执行以下操作...

        LoginResponse errorResponse = gson.fromJson(response.errorBody().string(), LoginResponse.class);
    

    ...或使用拦截器

    addInterceptor(getMyErrorResponseInterceptor())
    
    
    protected Interceptor getMyErrorResponseInterceptor() {
        return new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Response response = chain.proceed(request);
                if (response.code() >= 400) {
    
                    // handle error
                }
    
                return response;
            }
        };
    }
    

    【讨论】:

    • 是的,我可以这样做,但我必须在所有改造回调中这样做。我可以用拦截器来代替吗?
    • 是的,你可以有一个拦截器来为所有调用捕获它。你要回来的是什么?它是 400 多条错误消息,带有预期的正文吗?
    • @kev 已更新以包含用于处理错误情况的拦截器
    • 目前我得到的是 403,但我也想处理其他非 200 代码。在拦截器中,我被困在我现在想用 errorBody 的内容填充响应正文的地方。我看到的是okhttp3.Response没有errorBody,在改造回调中传递的是retrofit2.Response,它有errorBody
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-12
    • 2020-10-19
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多