Appearance
Gateway 简介与核心作用
Spring Cloud Gateway 是 Spring Cloud 生态系统中的API网关服务,基于 Spring 5、Spring Boot 2 和 Project Reactor 等技术构建。它旨在为微服务架构提供一种简单、有效且统一的API路由管理方式。
Gateway 核心定位
Gateway 作为整个微服务架构的流量入口和边界控制器,所有外部请求首先到达网关,再由网关路由到具体的微服务。
Gateway 的核心作用
| 作用类别 | 具体功能 | 价值体现 |
|---|---|---|
| 路由转发 | 动态路由、路径重写、负载均衡 | 请求的智能分发和转发 |
| 安全防护 | 认证授权、IP黑白名单、防重放攻击 | 统一的安全屏障 |
| 流量治理 | 限流熔断、降级策略、流量染色 | 系统稳定性的保障 |
| 监控观测 | 链路追踪、日志收集、指标监控 | 全链路可观测性 |
| 业务赋能 | 参数校验、协议转换、响应缓存 | 业务逻辑的前置处理 |
基础路由配置
yaml
server:
port: 8080 # 网关端口
spring:
application:
name: api-gateway # 网关服务名
cloud:
# 配置Nacos注册中心(以Nacos为例)
nacos:
discovery:
server-addr: localhost:8848 # Nacos服务器地址
# 配置网关
gateway:
# 开启从注册中心动态创建路由的功能
discovery:
locator:
enabled: true # 启用动态路由
lowerCaseServiceId: true # 使用小写服务名,可选,默认为false(大写服务名)。开启后,可通过 http://网关地址:端口/微服务名(小写)/** 格式访问
# 配置静态路由
routes:
# 路由1:订单服务
- id: order-service-route
uri: lb://order-service
predicates:
- Path=/order/**
- Method=GET,POST # 限制请求方法
# 路由2:支付服务
- id: payment-service-route
uri: lb://payment-service
predicates:
- Path=/pay/**
# 暴露监控端点(可选,用于查看路由信息)
management:
endpoints:
web:
exposure:
include: gateway,health,info # 暴露gateway端点可查看路由信息断言(Predicate)的使用
yaml
spring:
cloud:
gateway:
routes:
- id: complex-route
uri: lb://target-service
predicates:
# 路径匹配
- Path=/api/v1/**
# 时间窗口
- After=2023-01-20T08:00:00.000+08:00
- Before=2023-12-31T23:59:59.000+08:00
# 请求方法
- Method=GET,POST
# 请求头匹配
- Header=X-Request-Id, \\d+
# Cookie匹配
- Cookie=token, .+
# 查询参数
- Query=version, v\\d+
# 客户端IP
- RemoteAddr=192.168.1.1/24
# 权重路由
- Weight=group-a, 80基于Java DSL的动态路由
java
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("product_route", r -> r
.path("/api/products/**") // 匹配 /api/products 路径
.filters(f -> f // 添加过滤器
.stripPrefix(1)
.addRequestHeader("X-Request-From", "gateway")
.circuitBreaker(config -> config
.setName("productCircuitBreaker")
.setFallbackUri("forward:/fallback/product")
)
)
.uri("lb://product-service") // 路由到 product-service 服务
)
.route("auth_route", r -> r
.path("/auth/**") // 匹配 /auth 路径
.uri("lb://auth-service") // 路由到 auth-service 服务
)
.build();
}
}Gateway 的内置 Filter
内置过滤器配置即可使用:
yaml
filters:
# 1. 请求头处理
- AddRequestHeader=X-Gateway-Route, user-service
- AddRequestParameter=source, gateway
- RemoveRequestHeader=User-Agent
# 2. 路径处理
- StripPrefix=2
- PrefixPath=/api/v1
# 3. 响应处理
- AddResponseHeader=X-Response-Time, $(currentTimeMillis)
- DedupeResponseHeader=Access-Control-Allow-Origin
# 4. 重试机制
- name: Retry
args:
retries: 3
methods: GET,POST
exceptions: java.io.IOException,java.util.concurrent.TimeoutException
# 5. 限流保护
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒令牌数
redis-rate-limiter.burstCapacity: 20 # 令牌桶容量
key-resolver: "#{@ipKeyResolver}" # 限流键解析器自定义全局过滤器GlobalFilter
java
@Component
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
// 判断请求路径,决定是否执行过滤逻辑。示例:排除特定路径
if (path.startsWith("/public/")) {
return chain.filter(exchange); // 如果是公开路径,直接放行,不执行过滤逻辑
}
// 检查参数
String uname = request.getQueryParams().getFirst( "uname");
if(uname == null){
log.info("参数用户名为nu11,非法用户");
exchange.getResponse().setstatusCode(Httpstatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
// 验证通过,继续执行
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1; // 高优先级,按顺序执行全部的过滤器
}
}自定义路由过滤器GatewayFilter
- 实现 GatewayFilter 接口,通常也会实现 Ordered 接口来控制过滤器的执行顺序(order 值越小,优先级越高)。
java
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
public class RequestTimeFilter implements GatewayFilter, Ordered {
private static final String REQUEST_START_TIME = "requestStartTime";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. Pre-filter 逻辑:记录请求开始时间
exchange.getAttributes().put(REQUEST_START_TIME, System.currentTimeMillis());
// 2. 继续执行过滤器链,并在链执行完毕后执行 Post-filter 逻辑
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute(REQUEST_START_TIME);
if (startTime != null) {
long duration = System.currentTimeMillis() - startTime;
System.out.println("请求 " + exchange.getRequest().getURI().getRawPath() + " 处理耗时: " + duration + "ms");
// 通常这里会记录日志,而不是直接打印
}
})
);
}
@Override
public int getOrder() {
// 设置过滤器执行顺序,这里设置为最低优先级
return Ordered.LOWEST_PRECEDENCE;
}
}- 将此过滤器注册到路由:你需要通过 Java 配置(RouteLocator)将此过滤器绑定到特定路由。
java
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("api_route", r -> r.path("/api/**")
.uri("lb://backend-service")
// 将自定义过滤器添加到该路由
.filters(new RequestTimeFilter())
.id("api-with-timing"))
.build();
}
}自定义路由过滤器(工厂+配置)
通过继承 AbstractGatewayFilterFactory 来创建自定义过滤器工厂,这样你就可以在 YAML 中像使用内置过滤器一样配置它。
- 以下是一个模拟的认证过滤器工厂示例:
java
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.Arrays;
import java.util.List;
@Component // 将其声明为Spring组件
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.Config> {
// 构造函数
public AuthGatewayFilterFactory() {
super(Config.class);
}
// 指定配置文件中参数的顺序
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("enabled", "role");
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// 如果未启用,直接放行
if (!config.isEnabled()) {
return chain.filter(exchange);
}
// 模拟认证逻辑:检查请求头中是否有"Authorization"
String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");
if (!StringUtils.hasText(authHeader)) {
// 若未找到认证头,返回401未授权
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 这里可以添加更复杂的认证和授权逻辑,例如解析JWT,校验config中的role等
System.out.println("认证通过,进行角色校验: " + config.getRole());
// 认证通过,继续执行过滤器链
return chain.filter(exchange);
};
}
// 静态内部配置类,用于接收配置文件中的参数
public static class Config {
private boolean enabled;
private String role;
// Getter 和 Setter 方法
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
public String getRole() { return role; }
public void setRole(String role) { this.role = role; }
}
}- 创建好过滤器工厂后,你就可以在配置文件中通过其名称(类名去掉"GatewayFilterFactory"后缀,如 Auth)来使用它。
yaml
spring:
cloud:
gateway:
routes:
- id: secure_api_route
uri: lb://user-service
predicates:
- Path=/secure/**
filters:
# 使用自定义的认证过滤器,并传递参数
- name: Auth # 使用自定义过滤器工厂
args:
enabled: true
role: "ADMIN"集成Sentinel实现熔断降级
在微服务架构中,使用 Spring Cloud Gateway 作为 API 网关集成 Sentinel 进行流量控制,是保障系统稳定性的常见做法。
防护位置选择可以参考如下:
- 网关层:针对外部请求,进行粗粒度的全局流量控制和身份验证。
- 微服务层:针对服务间调用,进行细粒度的熔断降级和业务逻辑保护。
如果需要集成 Sentinel,可以参考其他微服务一样的配置来配置 Gateway 服务即可使用。但请注意,
spring-cloud-alibaba-sentinel-gateway依赖非常关键,它为网关提供了专门的适配支持。缺少它可能导致流控规则不生效。
xml
<!-- Sentinel Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Sentinel Gateway Adapter (关键) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>