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

Retrofit POST发送自定义对象数组如何序列化无类名标准JSON

问题根因

该问题和Gson配置无关。使用@FormUrlEncoded搭配@Field传参时,Retrofit默认会直接调用参数对象的toString()方法生成表单字段值,Kotlin data class默认的toString()实现输出就是带类名、属性键值对的格式,不会走Gson序列化流程,因此才会输出带类名的非标准格式。

解决方案

根据后端接口的格式要求,二选一即可:

方案1:保留表单提交格式,手动序列化JSON(推荐,适配当前接口要求)

不需要修改接口的application/x-www-form-urlencoded表单提交逻辑,只需要提前用Gson将列表对象序列化为标准JSON字符串,再传入@Field参数即可。

  1. 调整Retrofit接口定义,将diff参数类型改为String:
@FormUrlEncoded
@POST("/patch")
suspend fun insertTracks(
    @Field("diff") diff: String
): PlaylistResponse
  1. 发起请求前,手动用Gson序列化对象:
// 建议全局复用单例Gson实例,不要每次新建
val gson = Gson()
val operationList = listOf(
    PlaylistInsertOperation(
        tracks = listOf(
            TrackId(id = "39117009", albumId = "5034819"),
            TrackId(id = "89341636", albumId = "18635889")
        )
    )
)
// 序列化为标准JSON字符串
val diffJson = gson.toJson(operationList)
// 发起请求
api.insertTracks(diffJson)

该方案生成的请求参数完全符合接口要求:diff=[{"tracks":[{"id":"39117009","albumId":"5034819"},...]}]

方案2:改用JSON请求体(需后端支持)

如果后端接口支持接收application/json格式的请求体,可以去掉@FormUrlEncoded注解,直接用@Body传递对象,Retrofit会自动调用Gson完成序列化:

// 定义请求体结构
data class InsertTracksRequest(
    val diff: List<PlaylistInsertOperation>
)

@POST("/patch")
suspend fun insertTracks(
    @Body request: InsertTracksRequest
): PlaylistResponse

注意:该方案的请求体为纯JSON格式,和原表单提交格式差异较大,必须提前确认后端支持后再使用。

注意事项

给出的接口示例中albumId字段为数字类型,但当前TrackId定义中albumId为String类型,序列化后会带双引号变成字符串。如果接口要求数字类型,需要将TrackId的albumId字段类型修改为Long,避免参数类型校验失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:39:18