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

Retrofit 2 POST请求传Query参数遇类型转换异常求助

解决Retrofit 2.3.0中Android 6.0下@Query与@Body共存的类型转换异常问题

你遇到的是Retrofit在Android 6.0(API 23)上的兼容bug——当同时使用@Query和@Body注解时,底层序列化逻辑出现异常,导致请求体被错误解析为String而非Map,进而抛出java.lang.String cannot be cast to java.util.Map。而Android 7.0+系统因为配套的OkHttp/Retrofit底层依赖版本更高,修复了这个问题,所以能正常运行。

结合你提到的「接口仅识别作为请求体的Map参数,无法识别@Query或@QueryMap注解」的限制,给你几个可行的替代方案:

方案1:将area_id直接加入请求体的HashMap中

既然接口只认请求体里的参数,最直接的方式就是把area_id放到你已经构建的body里:

// 在构建body时添加area_id参数
body.put("area_id", PreferenceUtils.getAreaId(getActivity()));

// 修改接口定义,移除@Query参数
@POST("/oscarapi/basket/add-product/")
Call<Basket> addItemToBasket(@Body HashMap<String, Object> body);

这样既符合接口的参数识别规则,又完全避开了@Query带来的兼容问题。

方案2:将area_id作为URL路径参数传递

如果接口支持通过路径传递area_id,可以修改接口定义为:

@POST("/oscarapi/basket/add-product/{area_id}")
Call<Basket> addItemToBasket(@Path("area_id") int areaId, @Body HashMap<String, Object> body);

调用时直接传入areaId即可,这种方式也不会触发@Query和@Body的冲突问题。

方案3:手动拼接URL参数到请求地址

完全绕过Retrofit的@Query处理,自己手动把参数拼到URL上:

// 修改接口定义为动态URL
@POST
Call<Basket> addItemToBasket(@Url String url, @Body HashMap<String, Object> body);

// 调用时拼接完整URL
String requestUrl = "/oscarapi/basket/add-product/?area_id=" + PreferenceUtils.getAreaId(getActivity());
Api.getInstance().getEndPoint()
    .addItemToBasket(requestUrl, body)
    .enqueue(new Callback<Basket>() {
        // 回调逻辑...
    });

这种方式完全由你控制URL的组成,避免Retrofit底层的序列化异常。

为什么Android 6.0会出问题?

本质是Retrofit在旧版本Android系统上,处理@Query和@Body共存的请求时,序列化逻辑出现了兼容问题——错误地将Query参数的处理逻辑干扰到了Body的解析,导致原本的HashMap被当成String处理,最终触发类型转换异常。而Android 7.0+系统的OkHttp版本更新,修复了这个底层的兼容bug。

内容的提问来源于stack exchange,提问作者Hassan Imtiaz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:21:48