You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Java使用Retrofit2如何处理服务端返回的不一致响应

处理方案

你不需要为两种响应创建完全独立的外层数据类,当前解析报错的核心原因是服务端接口设计不规范:同一个result字段,成功时返回对象、失败时返回空数组,序列化库默认无法自动识别转换同名字段的不同类型。

推荐实现(通用可复用)

抽离通用响应基类,自定义反序列化逻辑适配多类型字段,一次配置所有接口都能复用:

  1. 定义泛型基类承接所有响应的公共字段
public class BaseResponse<T> implements Serializable {
    private boolean status;
    private T result;
    private String message; // 多数接口失败时会返回错误提示,可按需添加

    public boolean isSuccess() {
        return status;
    }

    public T getResult() {
        return result;
    }

    public String getMessage() {
        return message;
    }
}
  1. 将原本嵌套在User类里的ResultModel抽为独立的业务实体类,注意字段类型和服务端返回匹配:服务端返回的id是数值类型,不要定义为String,避免类型转换错误
public class UserInfo implements Serializable {
    private int id;
    private String name;
    private String email;
}
  1. 自定义Gson反序列化适配器,解析时先判断status值,再决定如何解析result字段
public class ResponseDeserializer<T> implements JsonDeserializer<BaseResponse<T>> {
    private final Class<T> resultClazz;

    public ResponseDeserializer(Class<T> resultClazz) {
        this.resultClazz = resultClazz;
    }

    @Override
    public BaseResponse<T> deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
        BaseResponse<T> response = new BaseResponse<>();
        JsonObject obj = json.getAsJsonObject();
        boolean status = obj.get("status").getAsBoolean();
        response.status = status;
        
        // 解析错误提示
        if (obj.has("message") && !obj.get("message").isJsonNull()) {
            response.message = obj.get("message").getAsString();
        }

        // 仅成功状态下解析result为业务对象,失败时result是空数组直接忽略,赋值为null
        if (status) {
            JsonElement resultEle = obj.get("result");
            if (resultEle != null && resultEle.isJsonObject()) {
                response.result = context.deserialize(resultEle, resultClazz);
            }
        }
        return response;
    }
}
  1. 给Retrofit配置Gson时注册该适配器,接口定义直接返回对应泛型的基类即可
Gson gson = new GsonBuilder()
        .registerTypeAdapter(
                TypeToken.getParameterized(BaseResponse.class, UserInfo.class).getType(),
                new ResponseDeserializer<>(UserInfo.class)
        )
        .create();

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("你的接口基地址")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();

// 接口定义
interface ApiService {
    @GET("user/info")
    Call<BaseResponse<UserInfo>> getUserInfo();
}

快速临时方案(适合小型项目/少量接口)

如果不想写自定义适配器,可以把result字段定义为JsonElement类型,拿到响应后手动判断类型转换:

public class UserResponse implements Serializable {
    private boolean status;
    private JsonElement result;

    public boolean isSuccess() {
        return status;
    }

    public UserInfo getResult() {
        if (status && result.isJsonObject()) {
            return new Gson().fromJson(result, UserInfo.class);
        }
        return null;
    }
}

这种方式实现简单,但每个接口都要写重复的转换逻辑,不适合接口多的项目。

补充说明

  • 不建议分别创建成功、失败两套响应类:Retrofit每个接口只能绑定固定的响应类型,无法根据返回内容自动切换解析类,反而会增加不必要的复杂度。
  • 最优方案是和服务端沟通统一字段类型:失败场景下result返回null而非空数组,从根源避免类型不匹配问题。

内容的提问来源于stack exchange,提问作者YeJong Choe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 09:45:29