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

Android Retrofit传递UserData实体类到服务器时数据为空问题

问题原因

核心问题是请求数据格式不匹配:

  • 用@Body传递UserData对象时,Retrofit会通过Gson转换器把对象序列化为JSON格式,请求头的Content-Type是application/json。
  • 你的服务器端只支持表单提交格式(x-www-form-urlencoded)——也就是键值对拼接的形式,这也是@FormUrlEncoded+@Field能正常工作的原因:这种方式发送的是表单格式,Content-Type为application/x-www-form-urlencoded。

服务器端无法解析JSON格式的请求体,自然获取不到任何参数,因此返回HTTP 500错误,提示所有值为null。

解决方案(保留对象传递的方式)

如果想继续用对象传递而非逐个字段写@Field,有两种可行方向:

方向1:修改服务器端,支持JSON格式解析

让后端开发调整接口,使其能接收application/json格式的请求体并解析JSON数据。这是RESTful接口的标准做法,也更适合后续业务扩展。

方向2:客户端调整,把对象转为表单格式发送

如果服务器暂时无法修改,可以在客户端把UserData对象转为表单键值对发送,无需逐个字段声明:

方法1:使用@FieldMap

修改API接口:

@FormUrlEncoded
@POST("sol_register.php")
fun registerUser(@FieldMap userMap: Map<String, String>): Call<UsersType>

调用时将UserData转为Map:

val userMap = mapOf(
    "username" to event.userData.username,
    "email" to event.userData.email,
    "password" to event.userData.password
)
val call = query.registerUser(userMap)

方法2:自定义转换器(适合多对象场景)

如果有多个接口需要用对象转表单,可以自定义Retrofit转换器,自动将数据类转为表单格式。或者直接使用现成的第三方转换器库,不过单接口场景下@FieldMap已经足够简便。

验证建议

你已经配置了HttpLoggingInterceptor.Level.BODY,可以查看两种请求的日志差异:

  • 用@Body时,Request Body是JSON字符串,Content-Type为application/json
  • 用@FormUrlEncoded时,Request Body是username=xxx&email=xxx&password=xxx的键值对形式,Content-Type为application/x-www-form-urlencoded

对比日志就能直观看到格式差异,也能验证解决方案是否生效。

内容的提问来源于stack exchange,提问作者Russell Sjoblom

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:05:13