SpringCloud - Spring Cloud 之 Gateway网关,Route路由,Predicate 断言,Filter 过滤器(十三)
Posted MinggeQingchun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud - Spring Cloud 之 Gateway网关,Route路由,Predicate 断言,Filter 过滤器(十三)相关的知识,希望对你有一定的参考价值。
阅读本文前可先参考
SpringCloud - Spring Cloud根/父项目,开发准备(二)_MinggeQingchun的博客-CSDN博客
SpringCloud - Spring Cloud 之 Gateway网关(十三)_MinggeQingchun的博客-CSDN博客
Web 有三大组件(监听器 过滤器 servlet),Spring Cloud GateWay 最主要的功能就是路由转发,而在定义转发规则时主要涉及了以下三个核心概念
1、Route(路由)
2、Predicate(断言)
3、Filter(过滤)
一、Routes路由配置
Gateway有两种配置路由方式
1、Java代码配置类路由
参考官网给出demo Spring Cloud Gateway
@SpringBootApplication
public class DemogatewayApplication
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder)
return builder.routes()
.route("path_route", r -> r.path("/get")
.uri("http://httpbin.org"))
.route("host_route", r -> r.host("*.myhost.org")
.uri("http://httpbin.org"))
.route("rewrite_route", r -> r.host("*.rewrite.org")
.filters(f -> f.rewritePath("/foo/(?<segment>.*)", "/$segment"))
.uri("http://httpbin.org"))
.route("hystrix_route", r -> r.host("*.hystrix.org")
.filters(f -> f.hystrix(c -> c.setName("slowcmd")))
.uri("http://httpbin.org"))
.route("hystrix_fallback_route", r -> r.host("*.hystrixfallback.org")
.filters(f -> f.hystrix(c -> c.setName("slowcmd").setFallbackUri("forward:/hystrixfallback")))
.uri("http://httpbin.org"))
.route("limit_route", r -> r
.host("*.limited.org").and().path("/anything/**")
.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))
.uri("http://httpbin.org"))
.build();
在 springcloud-7-service-eureka-gateway 模块总 自定义一个配置类 GatewayRouteConfig
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 GatewayRouteConfig
/**
* 代码的路由 和 application.yml文件 不冲突,都可以用
* 如果 uri后面给了一个访问地址 和匹配地址相同,就不会再拼接
*/
@Bean
public RouteLocator customRoiteLocator(RouteLocatorBuilder builder)
//以下url从B站中引用
return builder.routes()
.route("movie-id",r->r.path("/movie").uri("https://www.bilibili.com/movie/?spm_id_from=333.1007.0.0"))
.route("douga-id",r->r.path("/v/douga").uri("https://www.bilibili.com/v/douga/?spm_id_from=333.1007.0.0"))
.build();
启动springboot 类
输入访问 http://localhost:81/movie
即会跳转到相应 url 进行访问资源
2、application.properties 或 application.yml 配置文件
即 SpringCloud - Spring Cloud 之 Gateway网关(十三)_MinggeQingchun的博客-CSDN博客
文中的 三、Gateway应用方式
application.properties
server.port=81
#eureka注册中心首页的Application这一栏
spring.application.name=springcloud-7-service-eureka-gateway
#每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”
eureka.instance.lease-renewal-interval-in-seconds=2
#告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出
eureka.instance.lease-expiration-duration-in-seconds=10
#告诉服务端,服务实例以IP作为链接,不是取机器名
eureka.instance.prefer-ip-address=false
#注册服务实例ID,,服务ID必须唯一 springcloud-7-service-eureka-gateway
eureka.instance.instance-id=$spring.application.name:$server.port
#注册中心的链接地址 http://eureka8761:8761/eureka,http://eureka8762:8762/eureka,http://eureka8763:8763/eureka
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
#网关路由配置
#开启网关,默认开启
spring.cloud.gateway.enabled=true
#节点 routes 是一个List 对象,其中 routes 集合中中又包含多个对象,每个对象有三个属性(一个 索引[0]代表一个对象)
#路由 id,没有固定规则,但唯一
spring.cloud.gateway.routes[0].id=login-service-route
#匹配后提供服务的路由地址;uri统一资源定位符 url 统一资源标识符
spring.cloud.gateway.routes[0].uri=http://localhost:9001
#以下是断言条件,必选全部符合条件;断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
#断言,路径匹配,只要Path匹配上了/doLogin 就往 uri 转发 并且将路径带上 注意:Path 中 P 为大写
#也可以全局匹配,如 /service/**
spring.cloud.gateway.routes[0].predicates[0]=Path=/doLogin
#只能是 GET 请求时,才能访问
spring.cloud.gateway.routes[0].predicates[0]=Method=GET,POST
#配置第二个路由规则
spring.cloud.gateway.routes[1].id=admin-service-route
spring.cloud.gateway.routes[1].uri=http://localhost:9001
spring.cloud.gateway.routes[1].predicates[0]=Path=/doAdmin
spring.cloud.gateway.routes[1].predicates[0]=Method=GET,POST
#表明gateway开启服务注册和发现的功能,并且spring cloud gateway自动根据服务发现为每一个服务创建了一个router,这个router将以服务名开头的请求路径转发到对应的服务
spring.cloud.gateway.discovery.locator.enabled=true
#是将请求路径上的服务名配置为小写(服务注册的时候,向注册中心注册时将服务名转成大写了),如以/service/*的请求路径被路由转发到服务名为service的服务上
spring.cloud.gateway.discovery.locator.lower-case-service-id=true
application.yml
server:
port: 81
#eureka注册中心首页的Application这一栏
spring:
application:
name: springcloud-7-service-eureka-gateway
#网关路由配置
cloud:
gateway:
#开启网关,默认开启
enabled: true
#节点 routes 是一个List 对象,其中 routes 集合中中又包含多个对象,每个对象有三个属性(一个 索引[0]代表一个对象)
routes:
#路由 id,没有固定规则,但唯一
- id: login-service-route
#匹配后提供服务的路由地址;uri统一资源定位符 url 统一资源标识符
uri: http://localhost:9001
#以下是断言条件,必选全部符合条件;断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
predicates:
#断言,路径匹配,只要Path匹配上了/doLogin 就往 uri 转发 并且将路径带上 注意:Path 中 P 为大写
#也可以全局匹配,如 /service/**
- Path=/doLogin
#只能是 GET,POST 请求时,才能访问
- Method=GET,POST
#配置第二个路由规则
- id: admin-service-route
uri: http://localhost:9001
predicates:
- Path=/doAdmin
- Method=GET,POST
#表明gateway开启服务注册和发现的功能,并且spring cloud gateway自动根据服务发现为每一个服务创建了一个router,这个router将以服务名开头的请求路径转发到对应的服务
discovery:
locator:
enabled: true
#是将请求路径上的服务名配置为小写(服务注册的时候,向注册中心注册时将服务名转成大写了),如以/service/*的请求路径被路由转发到服务名为service的服务上
lower-case-service-id: true
eureka:
instance:
#每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”
lease-renewal-interval-in-seconds: 2
#告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出
lease-expiration-duration-in-seconds: 10
#告诉服务端,服务实例以IP作为链接,不是取机器名
prefer-ip-address: false
#注册服务实例ID,,服务ID必须唯一 springcloud-7-service-eureka-gateway
instance-id: $spring.application.name:$server.port
#注册中心的链接地址 http://eureka8761:8761/eureka,http://eureka8762:8762/eureka,http://eureka8763:8763/eureka
client:
service-url:
defaultZone: http://localhost:8761/eureka
3、Gateway 微服务名动态路由,负载均衡
我们设置的 routes的 uri 都是写死的,这样不符合微服务的要求,微服务是只要知道服务的名字,根据名字去找,且直接写死URI就没有负载均衡的效果
默认情况下 Gateway 会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路
由进行转发,从而实现动态路由的功能
uri 的协议(如 http 协议)为 lb(load Balance),表示启用 Gateway 的负载均衡功能。
lb://serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
#匹配后提供服务的路由地址;uri统一资源定位符 url 统一资源标识符
#uri 的协议为 lb(load Balance),表示启用 Gateway 的负载均衡功能
#lb://serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri;serviceName要和启动的微服务名保持一致
spring.cloud.gateway.routes[0].uri=lb://springcloud-7-service-eureka-gateway-login
#eureka注册中心首页的Application这一栏
spring:
application:
name: springcloud-7-service-eureka-gateway
#网关路由配置
cloud:
gateway:
#开启网关,默认开启
enabled: true
#节点 routes 是一个List 对象,其中 routes 集合中中又包含多个对象,每个对象有三个属性(一个 索引[0]代表一个对象)
routes:
#路由 id,没有固定规则,但唯一
- id: login-service-route
#匹配后提供服务的路由地址;uri统一资源定位符 url 统一资源标识符
#uri: http://localhost:9001
#uri 的协议为 lb(load Balance),表示启用 Gateway 的负载均衡功能
#lb://serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri;serviceName要和启动的微服务名保持一致
uri: lb://springcloud-7-service-eureka-gateway-login
#以下是断言条件,必选全部符合条件;断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
predicates:
#断言,路径匹配,只要Path匹配上了/doLogin 就往 uri 转发 并且将路径带上 注意:Path 中 P 为大写
#也可以全局匹配,如 /service/**
- Path=/doLogin
#只能是 GET,POST 请求时,才能访问
- Method=GET,POST
浏览器输入访问http://localhost:81/springcloud-7-service-eureka-gateway-login/doLogin
二、Predicate 断言
Gateway 启动时会去加载一些路由断言工厂(一个 boolean 表达式 )
我们可以通过上述官网查看断言表达式
断言就是路由添加一些条件(通俗的说,断言就是一些布尔表达式,满足条件的返回 true,不满足的返回 false)
Spring Cloud Gateway 将路由作为 Spring WebFlux HandlerMapping 基础架构的一部分进行匹配。
Spring Cloud Gateway 包括许多内置的路由断言工厂。所有这些断言都与 HTTP请求的不同属性匹配。可以将多个路由断言可以组合使用
Spring Cloud Gateway 创建对象时,使用 RoutePredicateFactory 创建 Predicate 对象,Predicate 对象可以赋值给 Route。
规则 | 实例 | 说明 |
---|---|---|
Path | - Path=/gate/,/rule/ | ## 当请求的路径为gate、rule开头的时,转发到http://localhost:9023服务器上 |
Before | - Before=2020-01-20T17:42:47.789-07:00[America/Denver] | 在某个时间之前的请求才会被转发到 http://localhost:9023服务器上 |
After | - After=2020-01-20T17:42:47.789-07:00[America/Denver] | 在某个时间之后的请求才会被转发 |
Between | - Between=2020-01-20T17:42:47.789-07:00[America/Denver],2020-01-21T17:42:47.789-07:00[America/Denver] | 在某个时间段之间的才会被转发 |
Cookie | - Cookie=chocolate, ch.p | 名为chocolate的表单或者满足正则ch.p的表单才会被匹配到进行请求转发 |
Header | - Header=X-Request-Id, \\d+ | 携带参数X-Request-Id或者满足\\d+的请求头才会匹配 |
Host | - Host=www.hd123.com | 当主机名为www.hd123.com的时候直接转发到http://localhost:9023服务器上 |
Method | - Method=GET | 只有GET方法才会匹配转发请求,还可以限定POST、PUT等请求方式 |
application.yml配置文件
server:
port: 81
spring:
application:
name: gateway-81
cloud:
gateway:
enabled: true #开启网关,默认是开启的
routes: #设置路由,注意是数组,可以设置多个,按照 id 做隔离
- id: user-service #路由 id,没有要求,保持唯一即可
uri: lb://provider #使用 lb 协议 微服务名称做负均衡
predicates: #断言匹配
- Path=/info/** #和服务中的路径匹配,是正则匹配的模式
- After=2020-01-20T17:42:47.789-07:00[Asia/Shanghai] #此断言匹配发生在指定 日期时间之后的请求,ZonedDateTime dateTime=ZonedDateTime.now()获得
- Before=2020-06-18T21:26:26.711+08:00[Asia/Shanghai] #此断言匹配发生在指定 日期时间之前的请求
- Between=2020-06-18T21:26:26.711+08:00[Asia/Shanghai],2020-06-18T21:32:26.711+08:00[Asia/Shanghai] #此断言匹配发生在指定日期时间之间的请求
- Cookie=name,xiaobai #Cookie 路由断言工厂接受两个参数,Cookie 名称和 regexp(一 个 Java 正则表达式)。此断言匹配具有给定名称且其值与正则表达式匹配的 cookie
- Header=token,123456 #头路由断言工厂接受两个参数,头名称和 regexp(一个 Java 正 则表达式)。此断言与具有给定名称的头匹配,该头的值与正则表达式匹配。
- Host=**.bai*.com:* #主机路由断言工厂接受一个参数:主机名模式列表。该模式是一 个 ant 样式的模式。作为分隔符。此断言匹配与模式匹配的主机头
- Method=GET,POST #方法路由断言工厂接受一个方法参数,该参数是一个或多个参数: 要匹配的 HTTP 方法
- Query=username,cxs #查询路由断言工厂接受两个参数:一个必需的 param 和一个 可选的 regexp(一个 Java 正则表达式)。
- RemoteAddr=192.168.1.1/24 #RemoteAddr 路由断言工厂接受一个源列表(最小大小 1), 这些源是 cidr 符号(IPv4 或 IPv6)字符串,比如 192.168.1.1/24(其中 192.168.1.1 是 IP 地址,24 是子网掩码)。
三、Filter 过滤器
Gateway 里面的过滤器和 Servlet 里面的过滤器,功能差不多,路由过滤器可以用于修改进入
Http 请求和返回 Http 响应
Gateway 中过滤器
1、按生命周期
pre 在业务逻辑之前
post 在业务逻辑之后
2、按种类
GatewayFilter 需要配置某个路由,才能过滤。如果需要使用全局路由,需要配置 DefaultFilters
GlobalFilter 全局过滤器,不需要配置路由,系统初始化作用到所有路由上
全局过滤器 统计请求次数;限流;token 的校验;ip 黑名单拦截 ;跨域本质(filter) ;144 开头的电话;限制一些 ip 的访问
1、自定义 GlobalFilter 全局过滤器
GlobalFilter 是一种作用于所有的路由上的全局过滤器,通过它,我们可以实现一些统一化的业务功能,例如权限认证、IP 访问限制等。当某个请求被路由匹配时,那么所有的 GlobalFilter 会和该路由自身配置的 GatewayFilter 组合成一个过滤器链
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.HashMap;
/**
* 自定义全局过滤器
*/
@Component
public class GlobalFilterConfig implements GlobalFilter, Ordered
/**
* 过滤方法
* 过滤器链模式;责任链模式
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
//针对请求的过滤,拿到请求的header、url、参数等
// HttpServletRequest 是web里面的
// ServerHttpRequest 是webFlux里面(响应式)
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
System.out.println("path====" + path);
HttpHeaders headers = request.getHeaders();
System.out.println("headers====" + headers);
String methodName = request.getMethod().name();
System.out.println("methodName====" + methodName);
//IPV4、IPV6地址
String hostName = request.getRemoteAddress().getHostName();
System.out.println("hostName====" + hostName);
String ip = request.getHeaders().getHost().getHostString();
System.out.println("ip====" + ip);
// 响应相关的数据
ServerHttpResponse response = exchange.getResponse();
//响应头设置编码
response.getHeaders().set("content-type","application/json;charset=utf-8");
HashMap<String ,Object> map = new HashMap<>(4);
map.put("code", HttpStatus.UNAUTHORIZED.value());
map.put("msg","你未授权");
ObjectMapper objectMapper = new ObjectMapper();
//将一个map转成一个字节数组
byte[] bytes = new byte[0];
try
bytes = objectMapper.writeValueAsBytes(map);
catch (JsonProcessingException e)
e.printStackTrace();
//通过buffer工厂将字节数组包装成一个数据包
DataBuffer wrap = response.bufferFactory().wrap(bytes);
return response.writeWith(Mono.just(wrap));
// 放行 到下一个过滤器
// return chain.filter(exchange);
/**
* 指定顺序的方法,越小越先执行
*/
@Override
public int getOrder()
return 0;
2、IP、Token认证拦截
1、token认证拦截
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
/**
* token校验
*/
@Component
public class TokenCheckFilter implements GlobalFilter, Ordered
/**
* 指定好放行的路径
*/
public static final List<String> ALLOW_URL = Arrays.asList("/springcloud-7-service-eureka-gateway-login/doLogin", "/myUrl","/doLogin");
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 和前端约定好 一般放在请求头里面 一般 key Authorization value bearer token
* 1、拿到请求url
* 2、判断放行
* 3、拿到请求头
* 4、拿到token
* 5、校验
* 6、放行/拦截
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if (ALLOW_URL.contains(path))
return chain.filter(exchange);
// 检查
HttpHeaders headers = request.getHeaders();
List<String> authorization = headers.get("Authorization");
if (!CollectionUtils.isEmpty(authorization))
String token = authorization.get(0);
if (StringUtils.hasText(token))
// 约定好的有前缀的 bearer token
String realToken = token.replaceFirst("bearer ", "");
if (StringUtils.hasText(realToken) && redisTemplate.hasKey(realToken))
return chain.filter(exchange);
// 拦截
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().set("content-type","application/json;charset=utf-8");
HashMap<String, Object> map = new HashMap<>(4);
// 返回401
map.put("code", HttpStatus.UNAUTHORIZED.value());
map.put("msg","未授权");
ObjectMapper objectMapper = new ObjectMapper();
byte[] bytes = new byte[0];
try
bytes = objectMapper.writeValueAsBytes(map);
catch (JsonProcessingException e)
e.printStackTrace();
DataBuffer wrap = response.bufferFactory().wrap(bytes);
return response.writeWith(Mono.just(wrap));
/**
* 这个顺序 最好在0附近 -2 -1 0 1
* @return
*/
@Override
public int getOrder()
return 1;
2、IP认证拦截
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
/**
* 网关里面 过滤器
* ip拦截
* 请求都有一个源头
* 电话 如:144 开头
* 请求------->gateway------->service
* 黑名单 black_list
* 白名单 white_list
* 根据数量
* 像具体的业务服务 一般黑名单
* 一般像数据库 用白名单
*/
@Component
public class IPCheckFilter implements GlobalFilter, Ordered
/**
* 网关的并发比较高,不要在网关里面直接操作mysql
* 后台系统可以查询数据库,用户量并发量不大
* 如果并发量大 可以查redis 或者 在内存中写好
*/
public static final List<String> BLACK_LIST = Arrays.asList("127.0.0.1", "144.128.139.137");
/**
* 1、获取到ip
* 2、校验ip是否符合规范
* 3、放行 OR 拦截
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
ServerHttpRequest request = exchange.getRequest();
String ip = request.getHeaders().getHost().getHostString();
// 查询数据库 看这个ip是否存在黑名单里面
if (!BLACK_LIST.contains(ip))
return chain.filter(exchange);
//拦截
//注:此处如果拦截IP,就要放开 GlobalFilter 的拦截
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().set("content-type","application/json;charset=utf-8");
HashMap<String, Object> map = new HashMap<>(4);
map.put("code", 438);
map.put("msg","你是黑名单");
ObjectMapper objectMapper = new ObjectMapper();
byte[] bytes = new byte[0];
try
bytes = objectMapper.writeValueAsBytes(map);
catch (JsonProcessingException e)
e.printStackTrace();
DataBuffer wrap = response.bufferFactory().wrap(bytes);
return response.writeWith(Mono.just(wrap));
@Override
public int getOrder()
return 0;
3、限流
限流就是限制一段时间内,用户访问资源的次数,减轻服务器压力,限流大致分为两种:
1、IP 限流(5s 内同一个 ip 访问超过 3 次,则限制不让访问,过一段时间才可继续访问)
2.、请求量限流(只要在一段时间内(窗口期),请求次数达到阀值,就直接拒绝后面来的访问了,
过一段时间才可以继续访问)(粒度可以细化到一个 api(url),一个服务)
限流模型:漏斗算法 ,令牌桶算法,窗口滑动算法 计数器算法
令牌桶算法
(1)所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
(2)根据限流大小,设置按照一定的速率往桶里添加令牌
(3)桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
(4)请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
(5)令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令
牌,以此保证足够的限流
Spring Cloud Gateway 已经内置了一个 RequestRateLimiterGatewayFilterFactory,可以直接使用。
目前 RequestRateLimiterGatewayFilterFactory 的实现依赖于 Redis,所以我们还要引入 spring-boot-starter-data-redis-reactive 依赖
<!--限流要引入 Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
配置类
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import reactor.core.publisher.Mono;
/**
* 自定义请求限流
*/
@Configuration
public class RequestRateLimiterConfig
// 针对某一个接口,ip来限流,如/doLogin,每一个ip,10s只能访问3次
@Bean
@Primary // 主候选的
public KeyResolver ipKeyResolver()
return exchange -> Mono.just(exchange.getRequest().getHeaders().getHost().getHostString());
// 针对这个路径来限制 /doLogin
// api 就是 接口 外面一般把gateway api网关 新一代网关
@Bean
public KeyResolver apiKeyResolver()
return exchange -> Mono.just(exchange.getRequest().getPath().value());
需要添加一个 @Primary // 主候选的 注解,不然报如下错误
启动快速访问
4、CORS跨域配置
@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);
或者 yml 文件配置
spring:
cloud:
gateway:
globalcors:
corsConfigurations: '[/**]': // 针对哪些路径
allowCredentials: true // 这个是可以携带 cookie
allowedHeaders: '*'
allowedMethods: '*' allowedOrigins: '*'
以上是关于SpringCloud - Spring Cloud 之 Gateway网关,Route路由,Predicate 断言,Filter 过滤器(十三)的主要内容,如果未能解决你的问题,请参考以下文章
Spring Cloud总结29.Zuul的FallBack回退机制
Oauth2.0 整合springCloud的Zuul 解决关键BUG 报错信息:Principal must not be null
Spring Cloud Alibaba - 02 SpringCloud SpringCloud Alibaba SpringBoot的生产版本选择