Spring WebFlux返回Kotlin数据类时为何使用CharSequenceEncoder而非KotlinSerializationJsonEncoder?
兄弟,我懂你遇到的这个坑——明明配置了Kotlinx Serialization当JSON序列化器,结果Spring WebFlux偏偏用CharSequenceEncoder来处理响应,日志里的输出看得人一脸懵。不过别担心,咱们一步步捋清楚问题出在哪,然后解决它!
先确认你的现有配置细节
先把你提供的代码按格式整理出来,方便咱们一起排查:
build.gradle.kts
plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.serialization) alias(libs.plugins.kotlin.spring) alias(libs.plugins.spring.boot) alias(libs.plugins.spring.dependency.management) } dependencies { implementation("org.springframework.boot:spring-boot-starter-webflux:3.5.3") { exclude(group = "com.fasterxml.jackson.core", module = "jackson-databind") exclude(group = "com.fasterxml.jackson.module", module = "jackson-module-kotlin") } implementation(libs.kotlinX.serialization) }
libs.versions.toml
[versions] spring = "3.5.3" kotlin = "2.2.0" serialization = "1.9.0" kotlinX-serialization = {module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" } [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-spring = { id = "org.jetbrains.kotlin.plugin.spring", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } spring-boot = { id = "org.springframework.boot", version.ref = "spring" } spring-dependency-management = { id = "io.spring.dependency-management", version = "1.1.7" }
控制器代码
@GetMapping("/trainSch", produces = [MediaType.APPLICATION_JSON_VALUE]) suspend fun getTrainSch( @RequestParam("trainNo") trainNumber: String ): ResponseEntity<TrainDetails> { return ResponseEntity.ok( TrainDetails( no = trainNumber, na = "Superfast Express", typ = 1, zn = 5, dly = 10, rake = "LHB", classes = 3, upd = "10:45 AM" ) ) }
数据类
@Serializable data class TrainDetails( val no: String, val na: String, val typ: Int, val zn: Int, val dly: Int, val rake: String, val classes: Int, val upd: String )
你的WebFlux配置Bean
@Bean fun webFluxConfigurer( encoder: KotlinSerializationJsonEncoder, decoder: KotlinSerializationJsonDecoder ): WebFluxConfigurer = object : WebFluxConfigurer { override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) { configurer.defaultCodecs().kotlinSerializationJsonEncoder(encoder) configurer.defaultCodecs().kotlinSerializationJsonDecoder(decoder) } }
问题根源分析
从日志和配置来看,核心问题是:Spring WebFlux没有优先使用KotlinSerializationJsonEncoder序列化你的TrainDetails对象,而是先把对象转成了JSON字符串,再用CharSequenceEncoder输出。
可能的原因有这几个:
- 手动配置的
WebFluxConfigurer和Spring Boot的自动配置冲突,导致Kotlinx Serialization的编码器没有被正确设置为首选 @EnableWebFlux注解关闭了Spring Boot的自动配置,包括Codec的自动注册- Codec链的优先级问题,
CharSequenceEncoder的优先级高于KotlinSerializationJsonEncoder
具体解决方法
方法1:先试试移除手动配置,依赖自动配置
Spring Boot 3.x+ 已经内置了Kotlinx Serialization的自动支持——当你排除Jackson依赖且引入kotlinx-serialization-json时,KotlinSerializationWebFluxAutoConfiguration会自动注册对应的编码器和解码器。
操作步骤:
- 删掉你自己定义的
webFluxConfigurerBean - 重启服务,调用接口查看日志
如果一切正常,日志里应该会显示KotlinSerializationJsonEncoder: Writing {...}而不是CharSequenceEncoder。
方法2:手动配置Codec(自动配置不生效时用)
如果自动配置没起作用,你可以手动调整Codec的注册方式,确保KotlinSerializationJsonEncoder被优先使用:
import kotlinx.serialization.json.Json import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.codec.CodecCustomizer import org.springframework.http.codec.json.KotlinSerializationJsonDecoder import org.springframework.http.codec.json.KotlinSerializationJsonEncoder @Configuration class WebFluxCodecConfig { @Bean fun kotlinSerializationCodecCustomizer(): CodecCustomizer { // 自定义Kotlinx Serialization的Json配置 val jsonConfig = Json { ignoreUnknownKeys = true // 忽略未知字段,增强兼容性 prettyPrint = false // 生产环境建议关闭格式化 } val jsonEncoder = KotlinSerializationJsonEncoder(jsonConfig) val jsonDecoder = KotlinSerializationJsonDecoder(jsonConfig) return CodecCustomizer { configurer -> // 注册自定义编码器到Codec链,确保优先级 configurer.customCodecs().register(jsonEncoder) configurer.customCodecs().register(jsonDecoder) // 替换默认的Kotlin Serialization Codec val defaultCodecs = configurer.defaultCodecs() defaultCodecs.kotlinSerializationJsonEncoder(jsonEncoder) defaultCodecs.kotlinSerializationJsonDecoder(jsonDecoder) } } }
方法3:检查是否启用了@EnableWebFlux
如果你在配置类或启动类上添加了@EnableWebFlux注解,这会完全关闭Spring Boot的WebFlux自动配置,包括Codec的自动注册。
解决:如果没有特殊的全局WebFlux配置需求,建议移除@EnableWebFlux注解,让Spring Boot的自动配置帮你处理Codec的注册。
验证结果
修改完成后,重启服务调用/trainSch?trainNo=12345接口:
- 查看TRACE级别日志,应该会看到
KotlinSerializationJsonEncoder: Writing {...}的输出 - Postman里的响应内容依然保持正确的JSON格式
内容来源于stack exchange

