Feign中Post请求自动转为Get踩坑记录

在使用Feign时,使用@RequestParam注解在POST或PUT请求中会导致请求被转换为GET,而GET请求携带body会变成POST。为解决此问题,可以遵循接口规范,只在GET中使用查询参数,在POST和PUT中使用body,或者自定义Feign拦截器来修正请求类型。添加拦截器时需在请求中添加特定header来标识请求类型。

Feign请求方式

在使用Feign的过程中,有时候会用到post请求和put请求,正常来说,这两种请求使用body传递参数不会有什么问题,但是如果使用@RequestParam传递参数的话,feign会将请求转为Get请求

同理,如果在使用Get请求的时候传递了body参数,那么,真实发送的其实是Post请求

如果在使用的过程中遇到类型的情况可以从这方面考虑下原因

示例

@PostMapping("/user/verifyOnly")
R<Boolean> verifyOnly(@RequestParam("phone") String phone);
// feign会按get请求发送
@GetMapping("/user/ancestor")
R<List<SysUser>> ancestorUsers(@RequestBody UserDTO userDTO);
// feign会按Post请求发送

也就是说,feign不会按Mapping的类型来进行发送请求,会根据参数类型自动转换为对应类型的请求,然后进行发送

解决方案

1、严格按照要求编写接口,Get请求中不加body参数,Post请求和Put请求需要加body参数

2、自定义拦截器,在拦截器中将body传递进去

package com.ralph.common.feign.config;


import feign.Request;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;

@Component
public class FeignRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate template) {
        // 处理POST请求的时候转换成了GET的bug
        if (HttpMethod.POST.name().equals(template.method()) && template.requestBody().length() == 0 && !template.queries().isEmpty()) {
            // 获取请求头信息
            Boolean isPost = Optional.of(template.headers()).map(item -> item.get("ralph-cus-header"))
                    .map(item -> item.contains("post"))
                    .orElse(false);
            if (isPost){
                StringBuilder builder = new StringBuilder();
                Map<String, Collection<String>> queries = template.queries();
                Iterator<String> queriesIterator = queries.keySet().iterator();

                while (queriesIterator.hasNext()) {
                    String field = queriesIterator.next();
                    Collection<String> strings = queries.get(field);
                    // 由于参数已经做了url编码处理,这里直接拼接即可
                    builder.append(field + "=" + StringUtils.join(strings, ","));
                    builder.append("&");
                }
                template.body(Request.Body.encoded(builder.toString().getBytes(), template.requestCharset()));
                template.queries(null);
            }
        }
    }
}

这么使用的话,需要在feign中增加@RequestHeader("ralph-cus-header") String cusHeader参数,值为post


👍 欢迎前往博客主页查看更多内容

👍 如果觉得不错,期待您的点赞、收藏、评论、关注

👍 ​ 如有错误欢迎指正!

👍 ​ Gitee地址:https://gitee.com/ralphchen/ralph-cloud

<think>我们正在处理用户关于Feign是否会将POST请求转化为GET请求的问题。根据提供的引用信息,实际上用户遇到的典型问题是FeignGET请求变成POST请求(而非POSTGET)。但用户明确提问的是POST是否会变GET,因此需要明确回答并解释相关机制。 关键点分析: 1. 引用[1][2][3]都描述了Feign在发送GET请求时(特别是当参数为对象时)会自动转换为POST请求的现象。 2. 引用[4]解释了原因:Feign默认使用的连接工具(可能是JDK的HttpURLConnection)在处理带有body的请求时,如果使用GET方法,会强制将其转换为POST方法。 3. 引用[4]同时提供了两种解决方案: a. 使用`@SpringQueryMap`注解来传递多个参数(这样就不会有body,而是将参数放在URL上) b. 更换Apache HttpClient作为Feign的底层客户端(因为Apache HttpClient允许在GET请求中发送body,虽然不符合HTTP规范,但可以避免Feign强制转换) 现在针对用户的问题:Feign是否会将POST请求自动转化为GET请求? - 根据上述引用和Feign的机制,Feign本身不会将POST请求转化为GET请求。因为POST请求本身就是带有body的,而Feign处理POST请求时不会强制转换方法(因为POST方法允许有body)。 - 反过来,只有当使用GET方法却试图传递一个body体时,Feign才会强制将GET转换为POST(因为HTTP规范中GET请求不应该带body,而Feign的默认实现遵循了这一规范)。 因此,结论是:Feign不会将POST请求自动转化为GET请求,但存在将GET请求转化为POST请求的情况(当GET请求包含body时)。 如果用户遇到POST请求被转化为GET请求的情况(与引用中描述的情况相反),那可能是其他原因造成的,例如: - 错误配置了Feign的method属性(如注解写错) - 使用了错误的注解(如本应使用@PostMapping却用了@GetMapping) - 其他框架的干扰(如网关、过滤器等) 但根据提供的引用,没有证据表明Feign有将POST转为GET的机制。 回答结构: 1. 直接回答问题:Feign不会将POST请求自动转化为GET请求。 2. 解释Feign在什么情况下会发生方法转换:只有GET请求带body时会转为POST。 3. 解释为什么会有这样的转换(引用4的原因)。 4. 如果用户遇到POSTGET的情况,可能的原因是什么(虽然不是Feign的默认行为,但也要考虑其他可能性)。 5. 给出如何避免方法转换的建议(针对GET被转POST的情况,因为这是常见问题,且引用中提供了解决方案)。 同时,根据用户之前的问题(用户上次的问题是关于GETPOST的),我们也可以推测用户可能是遇到了相反的情况,所以需要明确说明。 最后,生成相关问题。 </think>### Feign 请求方法转换问题解析 #### 现象说明 Feign **不会将 POST 请求自动转化为 GET 请求**,但存在反向转换问题: 1. **GET 被转 POST 是已知问题** 当 GET 请求使用对象参数时(如 `@GetMapping("/api") Result get(User user)`),Feign 默认会将 GET 强制转换为 POST 请求[^1][^2][^3] ```java // 错误示例:GET 请求带对象参数 → 实际发送 POST @GetMapping("/get") User get(User user); // 触发方法转换 ``` 2. **POSTGET 无已知案例** 在标准使用场景中,Feign 不会将 `@PostMapping` 声明的方法转换为 GET 请求POST 请求始终以 HTTP POST 方法发送。 --- #### 底层机制分析 Feign 方法转换的根本原因: $$ \text{HTTP 规范限制} + \text{Feign 实现逻辑} = \text{方法转换} $$ 1. **HTTP 规范约束** RFC 7231 规定 GET 请求不应包含请求体,部分 HTTP 客户端库强制遵循此规范[^4] 2. **Feign 的默认行为** 使用 JDK 原生 `HttpURLConnection` 时: - 检测到 GET 请求包含非空 body → 自动转换为 POST - POST 请求不受影响 --- #### 解决方案(针对 GET 被转 POST) 1. **`@SpringQueryMap` 注解方案** ```java @GetMapping("/get") User get(@SpringQueryMap User user); // 参数转为 URL 查询参数 ``` 2. **更换 HTTP 客户端** 在配置中启用 Apache HttpClient: ```yaml feign: httpclient: enabled: true ``` ```xml <!-- 依赖 --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency> ``` 3. **手动拼接 URL 参数** ```java @GetMapping("/get?name={name}&age={age}") User get(@PathVariable String name, @PathVariable Integer age); ``` --- #### 诊断 POST 意外变 GET 的方法 若观察到 POST 请求转为 GET,建议检查: 1. **注解声明** 确认接口方法是否误用 `@GetMapping` ```java // 错误:GET 注解配 POST 操作 @GetMapping("/create") void createUser(User user); ``` 2. **网关规则** 检查 API Gateway 是否配置了请求方法重写规则 3. **拦截器干扰** 审查自定义 `RequestInterceptor` 是否修改了请求方法 ```java public void apply(RequestTemplate template) { template.method("GET"); // 危险:强制改写方法 } ``` --- > **关键结论**: > Feign 存在 GETPOST自动转换机制,但 **POSTGET 的转换不是 Feign 的默认行为**。出现后者时需排查注解声明、网关配置或自定义拦截器逻辑[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值