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

使用Retrofit通过PUT请求发送Enum时出现HTTP 400错误排查

问题原因及解决方案

核心问题:请求体格式与API要求不匹配

你直接将TaskState枚举作为@Body参数发送,Gson默认会把它序列化成纯字符串(比如"NOT_ASSIGNED"),但目标API的editTaskState接口要求的是包含指定字段的JSON对象(而非纯字符串),同时可能还要求枚举值使用小写蛇形命名(比如not_assigned),这两点都不符合API的格式规范,因此返回HTTP 400错误。

具体解决方案

1. 修正请求体结构:创建包装类

API期望的请求体是类似这样的JSON结构:

{
  "state": "not_assigned"
}

你需要创建一个包装类来匹配这个结构:

data class TaskStateRequest(
    val state: TaskState
)

然后修改Retrofit的接口方法,用这个包装类作为请求体:

@PUT("/project/76fd04cc-ae1e-4589-8fe7-11c4f16ce067/task/{taskId}/state/")
suspend fun updateState(
    @Path("taskId") taskId: String,
    @Body stateRequest: TaskStateRequest
)

调用时传入TaskStateRequest(TaskState.NOT_ASSIGNED)即可。

2. 修正枚举值的序列化格式(适配API命名要求)

如果API要求枚举值是小写蛇形(比如not_assigned而非NOT_ASSIGNED),需要给Gson添加自定义枚举适配器,统一转换格式:

class TaskStateAdapter : TypeAdapter<TaskState>() {
    override fun write(out: JsonWriter, value: TaskState) {
        val apiValue = when(value) {
            TaskState.NOT_ASSIGNED -> "not_assigned"
            TaskState.IN_PROGRESS -> "in_progress"
            TaskState.CLOSED -> "closed"
            TaskState.DELETED -> "deleted"
        }
        out.value(apiValue)
    }

    override fun read(`in`: JsonReader): TaskState {
        val value = `in`.nextString()
        return when(value) {
            "not_assigned" -> TaskState.NOT_ASSIGNED
            "in_progress" -> TaskState.IN_PROGRESS
            "closed" -> TaskState.CLOSED
            "deleted" -> TaskState.DELETED
            else -> throw IllegalArgumentException("Unknown task state: $value")
        }
    }
}

然后在构建Gson实例时注册这个适配器:

val gson = GsonBuilder()
    .registerTypeAdapter(TaskState::class.java, TaskStateAdapter())
    .create()

最后将这个Gson传给Retrofit的转换器工厂:

Retrofit.Builder()
    .baseUrl("你的API基础地址")
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()

3. 验证实际请求内容(可选但推荐)

添加OkHttp的日志拦截器,打印出实际发送的请求体,对比API文档要求能快速定位问题:

val loggingInterceptor = HttpLoggingInterceptor().apply {
    level = HttpLoggingInterceptor.Level.BODY
}
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(loggingInterceptor)
    .build()

将这个okHttpClient配置到Retrofit中,就能在日志里看到完整的请求内容,确认是否符合API规范。

内容的提问来源于stack exchange,提问作者mikolaj-jalocha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 12:16:07