07 Feign拼接请求地址

本文介绍了如何利用Feign实现服务发现和自动拼接HTTP请求地址,将原本硬编码在Controller中的服务调用地址转移到独立的Client客户端,简化代码并提高可维护性。通过在consumer-demo项目中引入spring-cloud-starter-openfeign坐标,配置application.yml,创建启动类及各层文件,包括pojo、client和controller,最后进行测试验证。

Feign主要作用:自动根据参数拼接http请求地址。
将原先 controller 中写死的调用服务地址 ,拆分单独写client客户端,调用时直接注入。

服务发现(consumer-demo)

添加spring-cloud-starter-openfeign坐标

导入坐标(openfeign)
  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud_parent</artifactId>
        <groupId>li.chen.com</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>consumer_demo</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
</project>
配置文件
  • application.yml
spring:
  application:
    name: consumer_demo

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

    # 获取服务地址列表间隔时间,默认30秒
    registry-fetch-interval-seconds: 10

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000   # 延迟?
      circuitBreaker:
        errorThresholdPercentage: 50 # 触发熔断错误比例阈值,默认值50%
        sleepWindowInMilliseconds: 10000 # 熔断后休眠时长,默认值5秒
        requestVolumeThreshold: 10 # 熔断触发最小请求次数,默认值是20

springboot启动类
  • ConsumerApplication
package li.chen.com.consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableDiscoveryClient   //开启Eureka客户端发现功能
@SpringBootApplication
@EnableFeignClients  //开启Feign功能
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

各层文件

pojo层

  • User
package li.chen.com.consumer.pojo;

import lombok.Data;

import java.util.Date;

/**
 * @ClassName: User
 * @Description 接收数据,不进行数据库交互,故不需要加user_service里的那些注解
 **/
@Data
public class User {

    private Integer id;

    private String userName;

    private String passWord;

    private Date birthday;
}

client层

package li.chen.com.consumer.client;

import li.chen.com.consumer.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

//声明当前类是一个Feign客户端,指定服务名为UserService
@FeignClient("UserService")
public interface UserClient {

    // http://UserService/1   拼接的路径--》是UserService服务提供的路径
    @GetMapping("/UserController/{id}")
    User queryById(@PathVariable Long id);

}

controller层

  • ConsumerFeignController
package li.chen.com.consumer.controller;

import li.chen.com.consumer.client.UserClient;
import li.chen.com.consumer.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("ConsumerFeignController")
public class ConsumerFeignController {

    @Autowired
    private UserClient userClient;

    @GetMapping("/{id}")
    public User queryById(@PathVariable Long id){
        return userClient.queryById(id);
    }

}


测试

启动UserApplication9090
启动 EurekaServerApplication
启动 ConsumerApplication
访问 http://localhost:8080/ConsumerFeignController/2
在这里插入图片描述

<think>我们正在处理用户关于Feign是否会将POST请求转化为GET请求的问题。根据提供的引用信息,实际上用户遇到的典型问题是Feign将GET请求变成了POST请求(而非POST变GET)。但用户明确提问的是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. 如果用户遇到POST变GET的情况,可能的原因是什么(虽然不是Feign的默认行为,但也要考虑其他可能性)。 5. 给出如何避免方法转换的建议(针对GET被转POST的情况,因为这是常见问题,且引用中提供了解决方案)。 同时,根据用户之前的问题(用户上次的问题是关于GET变POST的),我们也可以推测用户可能是遇到了相反的情况,所以需要明确说明。 最后,生成相关问题。 </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. **POST 转 GET 无已知案例** 在标准使用场景中,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 存在 GET → POST 的自动转换机制,但 **POST → GET 的转换不是 Feign 的默认行为**。出现后者时需排查注解声明、网关配置或自定义拦截器逻辑[^4]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岿然如故

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值