Gateway - 网关
字数: 0 字 时长: 0 分钟
Spring Cloud Gateway 是 Spring Cloud 开源的网关组件,其底层使用 Netty 作为网络通信框架,在微服务架构中充当前端入口点的角色,实习了路由转发、请求过滤、负载均衡等功能。
原理
Spring Cloud Gateway 通过过滤器(Filters)和路由(Routes)来处理请求。
- 过滤器:可以在请求到达目标服务前或返回客户端前进行拦截、修改
- 路由:用于决定请求的转发目标,通过断言(Predicate)来判断请求是否符合某个 Route 的条件
Spring Cloud Gateway 的优势
- 高性能与异步处理:基于 Spring WebFlux 和 Reactor,使用异步非阻塞的编程模型,适合高并发场景
- 与 Spring 生态无缝集成:Spring 官方组件,配置简便
- 灵活的路由与过滤器机制:支持通过请求路径、请求头、请求参数等多种方式进行路由转发,可以实现复杂的路由规则;支持丰富的内置过滤器(如添加请求头、重写路径、限流等),也可以自定义过滤器
依赖引入
也可以引入 loadbalancer 让网关负载均衡地分发请求
xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
基础配置
在 application.yml 配置全局跨域 以及请求路径前缀 /api/order/** ===> 转为 /**
yaml
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origin-patterns: '*'
allowed-headers: '*'
allowed-methods: '*'
routes:
- id: order-route
uri: lb://service-order
predicates:
- Path=/api/order/**
filters:
- RewritePath=/api/order/(?<segment>.*), /$\{segment}
- id: product-route
uri: lb://service-product
predicates:
- Path=/api/product/**
filters:
- RewritePath=/api/product/(?<segment>.*), /$\{segment}
路由 Route
路由配置项即 RouteDefinition
类的属性
断言 Predicate
Gateway 定义了一系列默认的断言工厂
自定义断言工厂
自定义断言工厂需要继承 AbstractRoutePredicateFactory<T>
类,重写 apply
方法,返回一个自定义的断言对象 GatewayPredicate
java
@Component
public class VipRoutePredicateFactory extends
AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {
public VipRoutePredicateFactory() {
super(Config.class);
}
// 1. 自定义 Config 属性
@Data
@Validated
public static class Config {
@NotEmpty
private String param;
@NotEmpty
private String value;
}
//2. 配置参数列表顺序
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("param", "value");
}
// 3. 重写 apply()
@Override
public Predicate<ServerWebExchange> apply(Config config) {
//localhost/search?q=haha&user=leifengyang
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
ServerHttpRequest request = serverWebExchange.getRequest();
String first = request.getQueryParams().getFirst(config.param);
if (StringUtils.hasText(first) && first.equals(config.value)) {
return true;
}
return false;
}
};
}
}
断言包括 Path Query 还有自定义的 Vip 断言工厂
yaml
routes:
- id: bing-route
uri: https://cn.bing.com/
predicates:
- name: Path
args:
patterns: /search
- name: Query
args:
param: q
regexp: haha
- name: Vip
args:
param: user
value: leifengyang
order: 3
路径为 /search 参数为 q=haha Vip参数 user=leifengyang 就成功被断言
过滤器
默认过滤器
将请求 /api/order/** 重写为 /**
yaml
- id: order-route
uri: lb://service-order
predicates:
- Path=/api/order/**
filters:
- RewritePath=/api/order/(?<segment>.*), /$\{segment}
全局过滤器
案例:定义全局过滤器记录所有请求处理花费时间
java
/**
* 全局过滤器,记录请求时间与响应时间差
*/
@Component
@Slf4j
public class RtGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
String uri = request.getURI().toString();
long start = System.currentTimeMillis();
log.info("请求【{}】开始:时间:{}",uri,start);
//================ 以上前置逻辑 ===========
Mono<Void> filter = chain.filter(exchange) // 放行 10s
.doFinally((result) -> {
// 响应式编程 后置逻辑
long end = System.currentTimeMillis();
log.info("请求【{}】结束:时间:{},耗时:{}ms",uri,end,end-start);
});
return filter;
}
@Override
public int getOrder() {
return 0;
}
}
自定义过滤器
自定义过滤器,每次响应之前添加一个一次性令牌,支持 uuid ,jwt 格式,可以在 yml 文件中配置
java
@Component
public class OnceTokenGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//每次响应之前添加一个一次性令牌,支持 uuid ,jwt 等格式
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = response.getHeaders();
String value = config.getValue();
if ("uuid".equalsIgnoreCase(value)) {
value = UUID.randomUUID().toString();
}
if ("jwt".equalsIgnoreCase(value)) {
value = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" +
".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6" +
"IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MT" +
"UxNjIzOTAyMiwiZXhwIjoxNTE2MjQyNjIyfQ" +
".SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
}
headers.add(config.getName(),value);
}));
}
};
}
}
在
application.yml
中配置自定义的过滤器 OnceToken 作为默认过滤器
yaml
spring:
cloud:
gateway:
routes:
- id: order-route
uri: lb://service-order
predicates:
- Path=/api/order/**
filters:
- RewritePath=/api/order/(?<segment>.*), /$\{segment}
order: 0
default-filters:
- AddResponseHeader=X-Powered-By, Spring Cloud Gateway
- OnceToken=X-Response-Token, jwt