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

Spring 6声明式WebClient复杂请求参数自定义序列化问题

解决方案:声明式WebClient处理复杂对象作为@RequestParam参数

问题根源

声明式WebClient的@RequestParam参数转换依赖Spring ConversionService,而非WebClient的codecs(codecs仅处理请求体/响应体的编解码)。Feign内置了复杂对象到查询参数字符串的转换逻辑,但Spring 6的声明式WebClient需要显式注册转换器。

正确实现方案

1. 注册全局Converter

创建配置类,注册自定义转换器,将ComplexFilterClass序列化为JSON字符串:

import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.convert.converter.Converter

@Configuration
class WebConversionConfig {
    @Bean
    fun complexFilterToStringConverter(objectMapper: ObjectMapper): Converter<ComplexFilterClass, String> {
        return Converter { filter ->
            // 使用Jackson将对象序列化为JSON字符串
            objectMapper.writeValueAsString(filter)
        }
    }
}

2. 配置WebClient(可选,局部生效)

如果不想全局注册转换器,可以为特定WebClient单独配置ConversionService:

import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.context.annotation.Bean
import org.springframework.core.convert.support.DefaultConversionService
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.support.WebClientAdapter
import org.springframework.web.service.invoker.HttpServiceProxyFactory

@Bean
fun customWebClient(objectMapper: ObjectMapper): WebClient {
    val conversionService = DefaultConversionService().apply {
        addConverter(Converter<ComplexFilterClass, String> { filter ->
            objectMapper.writeValueAsString(filter)
        })
    }

    return WebClient.builder()
        .baseUrl("http://your-api-base-url")
        .exchangeStrategies { strategies ->
            strategies.conversionService(conversionService)
        }
        .build()
}

// 创建声明式客户端代理
@Bean
fun someResourceClient(webClient: WebClient): SomeResourceClient {
    return HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient))
        .build()
        .createClient(SomeResourceClient::class.java)
}

3. 声明式客户端接口保持原签名

你的接口定义无需修改,转换器会自动处理参数转换:

import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.service.annotation.GetExchange

interface SomeResourceClient {
    @GetExchange("/url/to/resource")
    suspend fun someResource(
        @RequestParam("filter") filter: ComplexFilterClass
    ): Response<List<Resource>>
}

关键说明

  • 为什么之前的codecs配置无效?:WebClient的codecs负责处理请求体(如POST的JSON payload)和响应体的编解码,而@RequestParam属于URI查询参数,由ConversionService处理,两者是独立的机制。
  • 序列化格式自定义:如果后端期望的不是JSON字符串(如特定格式的查询参数串),只需修改Converter中的序列化逻辑即可(比如使用Jackson的ObjectWriter定制格式,或手动拼接参数)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 18:43:18