OpenFeign 与 Gateway
版本说明:本文以 Spring Boot 3 / Spring Cloud 新版本思路为主。很多旧教程会使用 bootstrap.yml、Ribbon 等写法,学习时可以看,但自己写新项目时更建议优先使用 Spring Cloud LoadBalancer、spring.config.import 等新写法。
6. OpenFeign:声明式服务调用

6.1 OpenFeign 是什么
OpenFeign 是一个声明式 HTTP 客户端。所谓声明式,就是你不用手写完整的 HTTP 请求过程,只需要定义一个接口,Spring Cloud 会帮你生成代理对象去调用远程服务。
没有 Feign 时,你可能要写:
java
restTemplate.getForObject("http://user-service/users/1", String.class);
用了 Feign 后,你可以写成接口,服务类只需要实现这个接口功能即可。
java
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/users/{id}")
String getUser(@PathVariable("id") Long id);
}
在业务代码里像调用本地方法一样调用:
java
@Service
public class OrderService {
private final UserClient userClient;
public OrderService(UserClient userClient) {
this.userClient = userClient;
}
public String getOrderUser(Long userId) {
return userClient.getUser(userId);
}
}
6.2 OpenFeign 调用流程
user-service LoadBalancer 注册中心 Eureka/Nacos OpenFeign 代理对象 order-service user-service LoadBalancer 注册中心 Eureka/Nacos OpenFeign 代理对象 order-service userClient.getUser(1) 根据 user-service 查询实例 返回实例列表 选择一个实例 返回目标地址 发起 HTTP 请求 /users/1 返回用户信息 返回方法结果
OpenFeign 主要负责服务内部之间的远程调用 , Gateway 是网关,是外部请求进入系统的统一入口。这两个很容易搞混
6.3 OpenFeign 简单部署流程
第一步:消费者服务添加依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
第二步:启动类开启 Feign
java
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
第三步:定义 Feign 接口
java
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/users/{id}")
String getUser(@PathVariable("id") Long id);
}
第四步:注入并调用
java
@RestController
@RequestMapping("/orders")
public class OrderController {
private final UserClient userClient;
public OrderController(UserClient userClient) {
this.userClient = userClient;
}
@GetMapping("/{id}")
public String getOrder(@PathVariable Long id) {
String user = userClient.getUser(1L);
return "order id = " + id + ", " + user;
}
}
6.4 OpenFeign 常见注意点
@FeignClient(name = "user-service")中的name一般写注册中心里的服务名。@PathVariable建议明确写变量名,例如@PathVariable("id")。- OpenFeign 默认适合服务间 HTTP 调用,不适合传输特别大的文件。
7. Gateway:网关服务

7.1 Gateway 是什么
Spring Cloud Gateway 是微服务系统的 API 网关。它通常位于客户端和后端服务之间,作为统一入口。
前端/客户端
Spring Cloud Gateway
user-service
order-service
product-service
Gateway 常见职责:
- 路由转发:根据路径把请求转发到不同服务;
- 统一认证:判断用户是否登录、Token 是否有效;
- 日志记录:记录请求耗时、IP、路径;
- 跨域处理:统一配置 CORS;
- 限流降级:保护后端服务;
- 请求/响应改写:添加请求头、修改路径等。
7.2 Gateway 的三个核心概念
| 概念 | 作用 | 举例 |
|---|---|---|
| Route 路由 | 定义请求转发到哪里 | /api/users/**转发到user-service |
| Predicate 断言 | 判断请求是否匹配这条路由 | Path、Method、Header、Host |
| Filter 过滤器 | 在请求前后做增强处理 | 鉴权、加请求头、日志、限流 |
一个请求进入 Gateway 后,大致流程如下:
Service Filter Chain Predicate Gateway Client Service Filter Chain Predicate Gateway Client 发送请求 /api/users/1 判断匹配哪条 Route 匹配 user-service 路由 执行 pre 过滤器 转发到 user-service 返回响应 执行 post 过滤器 返回结果
7.3 Gateway 简单部署流程
第一步:添加依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
如果要通过注册中心用服务名转发,还需要接入 Eureka 或 Nacos Discovery。
第二步:配置路由
以 Nacos 为例:
yaml
server:
port: 10010
spring:
application:
name: gateway-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- id: order-service-route
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
这里要理解几个点:
uri: lb://user-service表示通过负载均衡调用注册中心里的user-service。Path=/api/users/**表示路径匹配时才走这条路由。StripPrefix=1表示转发前去掉第一层路径,例如/api/users/1转成/users/1。
请求链路:
text
客户端请求:/api/users/1
Gateway 匹配:Path=/api/users/**
StripPrefix=1 后:/users/1
转发目标:lb://user-service/users/1
8. GatewayFilter、GlobalFilter 与自定义 Filter

8.1 GatewayFilter
GatewayFilter 是路由级过滤器,只对某一条或某几条路由生效。
例如:
yaml
spring:
cloud:
gateway:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- AddRequestHeader=X-Source, gateway
- StripPrefix=1
这个过滤器只对 user-service-route 生效。它会给转发到后端服务的请求添加请求头:
text
X-Source: gateway
常见内置 GatewayFilter:
| Filter | 作用 |
|---|---|
| AddRequestHeader | 添加请求头 |
| AddResponseHeader | 添加响应头 |
| StripPrefix | 去掉路径前缀 |
| PrefixPath | 添加路径前缀 |
| RewritePath | 重写路径 |
| RequestRateLimiter | 请求限流 |
| Retry | 请求失败重试 |
8.2 GlobalFilter
GlobalFilter 是全局过滤器,会对所有匹配到路由的请求生效。
它适合处理公共逻辑:
- 登录校验;
- Token 解析;
- 请求日志;
- 灰度标记;
- 统一添加请求头;
- 统计请求耗时。
举一个简单实现栗子
java
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || token.isBlank()) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1;
}
}
getOrder() 用来控制过滤器顺序。数值越小,优先级越高。
8.3 pre 与 post 过滤逻辑
Gateway 的过滤器通常可以分成两个阶段:
- pre 阶段:请求转发到后端服务之前执行。
- post 阶段:后端服务返回响应之后执行。
请求进入 Gateway
pre 过滤器:鉴权/日志/加请求头
转发到后端服务
post 过滤器:统计耗时/改响应头
返回客户端
pre 适合做:鉴权、参数校验、添加请求头、路径改写、限流。
post 适合做:响应日志、统计耗时、添加响应头、统一包装响应。
8.4 自定义 GatewayFilterFactory
如果你想写一个只在某些路由上生效的自定义过滤器,可以写自定义 GatewayFilterFactory。
示例:
java
@Component
public class CheckHeaderGatewayFilterFactory
extends AbstractGatewayFilterFactory<CheckHeaderGatewayFilterFactory.Config> {
public CheckHeaderGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String value = exchange.getRequest().getHeaders().getFirst(config.headerName);
if (value == null || value.isBlank()) {
exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
};
}
public static class Config {
private String headerName;
public String getHeaderName() {
return headerName;
}
public void setHeaderName(String headerName) {
this.headerName = headerName;
}
}
}
配置中使用:
yaml
spring:
cloud:
gateway:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- name: CheckHeader
args:
headerName: X-Token
命名规则要注意:
text
CheckHeaderGatewayFilterFactory -> 配置中写 CheckHeader
也就是说,类名一般以 GatewayFilterFactory 结尾,配置时去掉这个后缀。
8.5 自定义 GlobalFilter
如果逻辑对所有路由都生效,比如统一日志,可以写 GlobalFilter。
java
@Component
public class LogGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
long start = System.currentTimeMillis();
String path = exchange.getRequest().getURI().getPath();
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
long cost = System.currentTimeMillis() - start;
System.out.println("path=" + path + ", cost=" + cost + "ms");
}));
}
@Override
public int getOrder() {
return 0;
}
}
理解重点:
GatewayFilter 更像"某条路由的局部增强",GlobalFilter 更像"整个网关的全局拦截器"。
9. 请求链路串联
学了这么多概念,在这里做一个简单的知识串联吧~
假设用户访问订单详情:
text
GET /api/orders/1001
完整流程如下:
user-service OpenFeign order-service Nacos/Eureka Gateway Client user-service OpenFeign order-service Nacos/Eureka Gateway Client GET /api/orders/1001 GlobalFilter 鉴权、日志 Predicate 匹配 /api/orders/** 根据 order-service 查询实例 返回 order-service 实例列表 负载均衡转发请求 调用 UserClient.getUser(userId) 根据 user-service 查询实例 返回 user-service 实例列表 负载均衡调用 user-service 返回用户信息 返回结果 返回订单详情 post 过滤器记录耗时 返回响应
- Gateway:负责外部入口、路由、过滤器;
- Nacos/Eureka:负责服务注册与发现;
- LoadBalancer:负责从多个实例中选一个;
- OpenFeign:负责服务内部之间的声明式 HTTP 调用;
- Nacos Config:虽然不在请求链路中,但负责服务启动和运行时读取配置。

希望对你有所帮助~祝身体健康