SpringCloud组件之Gateway
网关的概述
API网关是一个服务器,是系统对外的唯一入口。
网关的作用:授权、日志、限流
SpringCloud Gateway的使用
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
application.yml
spring:
cloud:
gateway:
routes:
- id: mes_routh
predicates: //断言
- Path=/mes/**
filters: //过滤器
- StripPrefix=1
- Auto=Authorization
uri: lb://mes
SpringCloud Gateway的核心概念
Routes(路由)
predicates(断言)
当断言为true的时候才会进行路由,当存在多个断言的时候,断言之间的存在关系为&&关系
@Component
public class AutoRoutePredicateFactory extends AbstractRoutePredicateFactory<AutoRoutePredicateFactory.Config> {
public AutoRoutePredicateFactory() {
super(Config.class);
}
private static final String NAME_KEY = "name";
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
HttpHeaders headers = serverWebExchange.getRequest().getHeaders();
List<String> headerList = headers.get(config.getName());
if (headerList != null && headerList.size() > 0) {
if (!"null".equals(headerList.get(0).toLowerCase())){
return true;
}
}
return false;
}
};
}
public static class Config{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
Filter
Filter分为两类:GlobalFilter和RouteFilter
//@Order(0)
@Component
public class ActDefineGatewayFilterFactory extends AbstractGatewayFilterFactory<ActDefineGatewayFilterFactory.Config> {
public ActDefineGatewayFilterFactory() {
super(Config.class);
}
private static final String NAME_KEY = "name";
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY);
}
@Override
public GatewayFilter apply(Config config) {
//pre post
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("conf:" + config.getName());
//TODO 处理前
return chain.filter(exchange).then(Mono.fromRunnable(()->{
//TODO 处理后回调
System.out.println("回调完成");
}));
}
};
}
public static class Config{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
SpringCloud Gateway 限流
组件提供了关于redis的限流机制:
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-redis-reactive', version: '2.3.4.RELEASE'
application.yml
spring:
cloud:
routes:
- id: mes_routh
predicates:
- Path=/mes/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 2
redis-rate-limiter.requestedTokens: 1
其中采用了令牌桶算法。
SpringCloud Gateway 动态路由
组件:
compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.3.4.RELEASE'
配置:
management:
endpoints:
web:
exposure:
include: "*"
API
/actuator/gateway/routes
查看路由信息
[
{
"predicate": "(Hosts: [**.addrequestheader.org] && Paths: [/headers], match trailing slash: true)",
"route_id": "add_request_header_test",
"filters": [
"[[AddResponseHeader X-Response-Default-Foo = 'Default-Bar'], order = 1]",
"[[AddRequestHeader X-Request-Foo = 'Bar'], order = 1]",
"[[PrefixPath prefix = '/httpbin'], order = 2]"
],
"uri": "lb://testservice",
"order": 0
}
]
/actuator/gateway/refresh
刷新路由:POST请求
/gateway/routes/{id_route_to_create}
创建路由:POST请求
删除路由:DELETE请求
动态路由是基于内存进行存储的。如果要对路由进行持久化,需要重写RouteDefinitionRepository
@Component
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
private final static String GATEWAY_ROUTE_KEY = "gateway_dynamic_route";
@Autowired
RedisTemplate<String, String> redisTemplate;
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
List<RouteDefinition> routeDefinitionList = new ArrayList<>();
redisTemplate.opsForHash().values(GATEWAY_ROUTE_KEY).forEach(route -> {
routeDefinitionList.add(JSONObject.parseObject(route.toString(), RouteDefinition.class));
});
return Flux.fromIterable(routeDefinitionList);
}
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(routeDefinition -> {
redisTemplate.opsForHash().put(GATEWAY_ROUTE_KEY,routeDefinition.getId(), JSON.toJSONString(routeDefinition));
return Mono.empty();
});
}
@Override
public Mono<Void> delete(Mono<String> routeId) {
return routeId.flatMap(id ->{
if (redisTemplate.opsForHash().hasKey(GATEWAY_ROUTE_KEY,id)){
redisTemplate.opsForHash().delete(GATEWAY_ROUTE_KEY,id);
return Mono.empty();
}
return Mono.defer(()->Mono.error(new Exception("routeDefinition not found " + routeId)));
});
}
}