Spring OpenFeign使用form-urlencoded时请求体为空问题排查
Spring OpenFeign使用application/x-www-form-urlencoded时请求体为空的问题解决
问题现象
使用Spring OpenFeign调用Content-Type为application/x-www-form-urlencoded的接口时,请求体为空,日志明确显示0字节请求体。其他类型的Feign客户端均正常工作,仅表单编码场景出现此问题。
环境信息:
- Java 17
- Spring Boot 3.1.0
- Spring Cloud OpenFeign 4.0.3
相关代码片段
Feign端点定义
@PostMapping(value = "url", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) MpcsAuthResponse obtainAccessToken(@RequestBody MpcsTokenRequest request);
Feign日志输出
c.k.c.t.m.m.client.mpcs.MpcsClient -- [MpcsClient#obtainAccessToken] ---> POST <url> HTTP/1.1 11:16:47.532 [main] DEBUG c.k.c.t.m.m.client.mpcs.MpcsClient -- [MpcsClient#obtainAccessToken] Content-Type: application/x-www-form-urlencoded; charset=UTF-8 11:16:47.532 [main] DEBUG c.k.c.t.m.m.client.mpcs.MpcsClient -- [MpcsClient#obtainAccessToken] 11:16:47.532 [main] DEBUG c.k.c.t.m.m.client.mpcs.MpcsClient -- [MpcsClient#obtainAccessToken] 11:16:47.532 [main] DEBUG c.k.c.t.m.m.client.mpcs.MpcsClient -- [MpcsClient#obtainAccessToken] ---> END HTTP (0-byte body)
初始DTO(Record类型)
public record MpcsTokenRequest(@FormProperty("client_id") String clientId, @FormProperty("client_secret") String clientSecret, @FormProperty("grant_type") String grantType) { }
Feign客户端配置
public class MpcsClientConfiguration { @Bean Encoder formEncoder() { return new feign.form.FormEncoder(); } @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
排查过程
- 替换DTO为
String类型时,请求可正常发送,说明问题出在DTO的序列化环节 - 定位到Feign的form编码器无法正确处理Java Record类型的对象,导致表单数据无法生成,最终请求体为空
解决方案
将Record类型的DTO改为传统POJO类即可解决问题,示例如下:
public class MpcsTokenRequest { @FormProperty("client_id") private String clientId; @FormProperty("client_secret") private String clientSecret; @FormProperty("grant_type") private String grantType; // 必须提供无参构造方法 public MpcsTokenRequest() {} // 需提供所有字段的getter和setter方法 public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } public String getClientSecret() { return clientSecret; } public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } public String getGrantType() { return grantType; } public void setGrantType(String grantType) { this.grantType = grantType; } }
内容的提问来源于stack exchange,提问作者Borislav Stoilov
相关产品推荐
相关产品推荐

