
Spring Cloud Gateway 是Spring Cloud官方推出的第二代网关框架,定位于取代 Netflix Zuul。Spring Cloud Gateway 旨在为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的基本功能,例如说安全认证、监控、限流等等。
Spring Cloud Gateway 是由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。它不能在传统的 servlet 容器中工作,也不能构建成 war 包
官网文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/
Spring Cloud Gateway 的工作原理跟 Zuul 的差不多,最大的区别就是 Gateway 的 Filter 只有 pre 和 post 两种

客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关 Web 处理程序,此时处理程序运行特定的请求过滤器链。
过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre 过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行 post 过滤器逻辑。
spring:
application:
name: gateway-demo
#配置nacos注册中心地址
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
#设置路由:路由id、路由到微服务的uri、断言
routes:
- id: order_route #路由ID,全局唯一,建议配置服务名
uri: lb://mall-order #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/order/** # 断言,路径相匹配的进行路由 mall-order(ip:8020/api/v5) --> ip:8020/order/api/v5
- Header=X-Request-Id, \d+
- id: user_route #路由ID,全局唯一,建议配置服务名
uri: lb://mall-user #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/user/** # 断言,路径相匹配的进行路由
- Header=X-Request-Id, \d+

GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories

自定义过滤器工厂继承AbstractNameValueGatewayFilterFactory且我们的自定义名称必须要以GatewayFilterFactory结尾并交给spring管理
@Component
@Slf4j
public class CheckAuthGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
log.info("调用CheckAuthGatewayFilterFactory==="
+ config.getName() + ":" + config.getValue());
// TODO
return chain.filter(exchange);
};
}
}
gateway:
routes:
- id: order-route
uri: lb://order-service
predicates:
- Path=/order/**
- Header=X-Request-Id, \d+
filters:
- AddRequestHeader=X-Request-color, red
- CheckAuth=mxgender,man
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#global-filters

自定义全局过滤器自定义全局过滤器定义方式是实现GlobalFilter接口。每一个过滤器都必须指定一个int类型的order值,order值越小,过滤器优先级越高,执行顺序越靠前。GlobalFilter通过实现Ordered接口来指定order值
@Component
@Slf4j
public class CheckAuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取token
String token = exchange.getRequest().getHeaders().getFirst("token");
if (null == token) {
log.info("token is null");
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().add("Content-Type",
"application/json;charset=UTF-8");
// 401 用户没有访问权限
response.setStatusCode(HttpStatus.UNAUTHORIZED);
byte[] bytes = HttpStatus.UNAUTHORIZED.getReasonPhrase().getBytes();
DataBuffer buffer = response.bufferFactory().wrap(bytes);
// 请求结束,不继续向下请求
return response.writeWith(Mono.just(buffer));
}
//TODO 校验token进行身份认证
log.info("校验token");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 2;
}
}

spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#reactor-netty-access-logs
-Dreactor.netty.http.server.accessLogEnabled=true
通过yml配置的方式
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#cors-configuration
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- DELETE
- PUT
- OPTION
通过java配置的方式
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
spring cloud alibaba官方提供了RequestRateLimiter过滤器工厂,基于redis+lua脚本方式采用令牌桶算法实现了限流

redis-pom
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redis-reactiveartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
dependency>
redis-applicaiton
spring:
redis:
host: redis.localhost.com
password: xxxxxxx
port: 6379
database: 0
timeout: 5000
lettuce:
pool:
max-active: 8
max-wait: 10000
max-idle: 100
min-idle: 10
gateway-application
spring:
cloud:
gateway:
routes:
- id: order-route
uri: lb://order-service
predicates:
- Path=/order/**
- Header=X-Request-Id, \d+
filters:
- AddRequestHeader=X-Request-color, red
- CheckAuth=mxgender,man
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充速率
redis-rate-limiter.burstCapacity: 2 #令牌桶的总容量
key-resolver: "#{@keyResolver}" #使用SpEL表达式,从Spring容器中获取Bean对象
keyResolver-bean
@Configuration
public class RateLimiterConfig {
@Bean
KeyResolver keyResolver() {
//url限流
return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
//参数限流
// return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
}
lua 脚本

Gateway整合sentinel限流从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:
https://github.com/alibaba/Sentinel/wiki/网关限流
pom
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-sentinel-gatewayartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
applicaiton
server:
port: 8033
spring:
application:
name: sentinel-gateway-demo
main:
allow-bean-definition-overriding: true
#配置nacos注册中心地址
cloud:
nacos:
discovery:
server-addr: nacos.mendd.com:8848
namespace: dev
ephemeral: true
sentinel:
transport:
# 添加sentinel的控制台地址
dashboard: 127.0.0.1:8080
datasource:
gateway-flow-rules:
nacos:
server-addr: nacos.localhost.com:8848
dataId: ${spring.application.name}-gateway-flow-rules
groupId: SENTINEL_GROUP
data-type: json
rule-type: gw-flow
gateway-api-rules:
nacos:
server-addr: nacos.localhost.com:8848
dataId: ${spring.application.name}-gateway-api-rules
groupId: SENTINEL_GROUP
data-type: json
rule-type: gw-api-group
degrade-rules:
nacos:
server-addr: nacos.localhost.com:8848
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
data-type: json
rule-type: degrade
system-rules:
nacos:
server-addr: nacos.localhost.com:8848
dataId: ${spring.application.name}-system-rules
groupId: SENTINEL_GROUP
data-type: json
rule-type: system
gateway:
#设置路由:路由id、路由到微服务的uri、断言
routes:
- id: order_route #路由ID,全局唯一,建议配合服务名
uri: lb://order-service #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/order/**



http://localhost:8033/order/testgateway/1?name=mx
当通过 GatewayRuleManager 加载网关流控规则(GatewayFlowRule)时,无论是否针对请求属性进行限流,Sentinel 底层都会将网关流控规则转化为热点参数规则(ParamFlowRule),存储在 GatewayRuleManager 中,与正常的热点参数规则相隔离。转换时 Sentinel 会根据请求属性配置,为网关流控规则设置参数索引(idx),并同步到生成的热点参数规则中。
外部请求进入 API Gateway 时会经过 Sentinel 实现的 filter,其中会依次进行 路由/API 分组匹配、请求属性解析和参数组装。Sentinel 会根据配置的网关流控规则来解析请求属性,并依照参数索引顺序组装参数数组,最终传入 SphU.entry(res, args) 中。Sentinel API Gateway Adapter Common 模块向 Slot Chain 中添加了一个 GatewayFlowSlot,专门用来做网关规则的检查。GatewayFlowSlot 会从 GatewayRuleManager 中提取生成的热点参数规则,根据传入的参数依次进行规则检查。若某条规则不针对请求属性,则会在参数最后一个位置置入预设的常量,达到普通流控的效果。


private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream().map(filter -> {
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
return new OrderedGatewayFilter(gatewayFilter, order);
}
return gatewayFilter;
}).collect(Collectors.toList());
}
private static class GatewayFilterAdapter implements GatewayFilter {
private final GlobalFilter delegate;
GatewayFilterAdapter(GlobalFilter delegate) {
this.delegate = delegate;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("GatewayFilterAdapter{");
sb.append("delegate=").append(delegate);
sb.append('}');
return sb.toString();
}
}