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
相关产品推荐
相关产品推荐

