gateway网关入门级学习
gateway
目录旁边可以查询具体的目录结构和跳转
一.网关介绍
这样的架构,会存在着诸多的问题:
1.每个业务都会需要鉴权、限流、权限校验、跨域等逻辑,如果每个业务都各自为战,自己造轮子实现一遍,会很蛋疼,完全可以抽出来,放到一个统一的地方去做。
2.如果业务量比较简单的话,这种方式前期不会有什么问题,但随着业务越来越复杂,比如淘宝、亚马逊打开一个页面可能会涉及到数百个微服务协同工作,如果每一个微服务都分配一个域名的话,一方面客户端代码会很难维护,涉及到数百个域名,另一方面是连接数的瓶颈,想象一下你打开一个APP,通过抓包发现涉及到了数百个远程调用,这在移动端下会显得非常低效。
3.后期如果需要对微服务进行重构的话,也会变的非常麻烦,需要客户端配合你一起进行改造,比如商品服务,随着业务变的越来越复杂,后期需要进行拆分成多个微服务,这个时候对外提供的服务也需要拆分成多个,同时需要客户端配合你进行改造,非常蛋疼。
上面的这些问题可以借助API网关来解决
所谓的 API网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等等。
添加上API网关之后,系统的架构图变成了如下所示:
二.什么是Spring Cloud Gateway
网关作为流量的入口,常用的功能包括路由转发,权限校验,限流等。
Spring Cloud Gateway 是Spring Cloud官方推出的第二代网关框架,定位于取代 Netflix Zuul1.0。相比 Zuul 来说,Spring Cloud Gateway 提供更优秀的性能,更强大的有功能,非阻塞的。(Zuul1.0是阻塞,Zuul2.0是非阻塞,2.0的性能和gateway差不多)
Spring Cloud Gateway 是由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。它不能在传统的 servlet 容器中工作,也不能构建成 war 包。
Spring Cloud Gateway 旨在为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的基本功能,例如说安全认证、监控、限流等等。
2.1 Spring Cloud Gateway 功能特征
- 基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
- 动态路由:能够匹配任何请求属性;
- 支持路径重写;
- 集成 Spring Cloud 服务发现功能(Nacos、Eruka);
- 可集成流控降级功能(Sentinel、Hystrix);
- 可以对路由指定易于编写的 Predicate(断言)和 Filter(过滤器);
2.2 核心概念
- 路由(route)
路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组断言工厂、一组Filter组成。如果断言为真,则说明请求的URL和
配置的路由匹配。
- 断言(predicates)
Java8中的断言函数,SpringCloud Gateway中的断言函数类型是Spring5.0框架中的ServerWebExchange。断言函数允许开发者去定义
匹配Http request中的任何信息,比如请求头和参数等。
- 过滤器(Filter)
SpringCloud Gateway中的filter分为Gateway FilIer和Global Filter。Filter可以对请求和响应进行处理。
2.3 工作原理
执行流程大体如下:
-
Gateway Client向Gateway Server发送请求
-
请求首先会被HttpWebHandlerAdapter进行提取组装成网关上下文
-
然后网关的上下文会传递到DispatcherHandler,它负责将请求分发给RoutePredicateHandlerMapping
-
RoutePredicateHandlerMapping负责路由查找,并根据路由断言判断路由是否可用
-
如果过断言成功,由FilteringWebHandler创建过滤器链并调用
-
请求会一次经过PreFilter--微服务--PostFilter的方法,最终返回响应
三.Spring Cloud Gateway快速开始
3.1引入依赖
<!‐‐ gateway网关 Spring Cloud开发 ‐‐>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring‐cloud‐starter‐gateway</artifactId>
</dependency>
注意:会和spring-webmvc的依赖冲突,需要排除spring-webmvc
3.2yml配置
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
#gateway
gateway:
#路由规则
routes:
- id: order_route #路由的唯一标识,例如路由到order
uri: http://localhost:8020 #需要转发的地址
#断言规则 用于路由规则的匹配
predicates:
- Path=/order‐serv/** #当请求路径满足Path指定的规则时,才进行路由转发
#http://localhost:8088/order‐serv/order/add ——>路由到
#http://localhost:8020/order‐serv/order/add
filters:
- StripPrefix=1 #路由转发之前去掉第一层路径,即/order‐serv/
#- id: stock_route
四.Gateway整合nacos
4.1导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
四.Gateway整合nacos
方法一.(更灵活,有更高的使用性)
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
#gateway
gateway:
#路由规则
routes:
- id: order_route #路由的唯一标识,例如路由到order
uri: lb://order-service #需要转发的地址 lb: 使用nacos中的本地负载均衡策略
#(我们直接写服务地址维护十分麻烦,通过nacos使用服务调用)
#断言规则 用于路由规则的匹配
predicates:
- Path=/order‐serv/** #当请求路径满足Path指定的规则时,才进行路由转发
#http://localhost:8088/order‐serv/order/add ——>路由到
#http://order-service/order‐serv/order/add ->filter后
#http://order-service/order/add
filters:
- StripPrefix=1 #路由转发之前去掉第一层路径,即/order‐serv/
#- id: stock_route
方法二.(更方便,nacos的简单配置方法)
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
#gateway
gateway:
discovery:
locator:
enabled: true #是否启动自动识别nacos服务
#以nacos中注册的服务名为断言,且不需要配置filter,会自动去除对于的第一次断言。
#http://localhost:8088/order-service/order/add ->路由到
#http://order-service/order-service/order/add ->filter后
#http://order-service/order/add
五.内置路由断言工厂配置
(Route Predicate Factories)
作用: 当请求gateway的时候, 使用断言对请求进行匹配, 如果匹配成功就路由转发, 如果匹配失败就返回404类型:内置,自定义。
#gateway
gateway:
#路由规则
routes:
- id: order_route #路由的唯一标识,例如路由到order
uri: lb://order-service #需要转发的地址 lb: 使用nacos中的本地负载均衡策略
predicates:
- Path=/order/**
#http://localhost:8088/order/add ——>路由到
#http://order-service/order/add
#- After=2027-12-31T23:59:59.789+08:00[Asia/Shanghai]
#- Header=X-Request-Id,\d+ #请求头断言,例如这个:key为X-Request-Id,value为数字
#- Method=GET #请求方法断言
#- Query=name,zxy #http://localhost:8088/order/add?name=zxy
1.基于Datetime类型的断言工厂
此类型的断言根据时间做判断,主要有三个:
AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期
BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期
BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内
ZonedDateTime.now()可以得到当下地区的时间
- After=2019-12-31T23:59:59.789+08:00[Asia/Shanghai]
2.基于远程地址的断言工厂
RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中。
- RemoteAddr=192.168.1.1/24
3.基于Cookie的断言工厂
CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求
cookie是否具有给定名称且值与正则表达式匹配。
- Cookie=chocolate, ch.
4.基于Header的断言工厂
HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否具有给定名称且值与正则表达式匹配。
- Header=X-Request-Id,\d+ #后面正则表达式之前不能有无用的空格
5.基于Host的断言工厂
HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。
- Host=**.testhost.org
6.基于Method请求方法的断言工厂
MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。
- Method=GET
7.基于Path请求路径的断言工厂
PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。
- Path=/order/**
#http://localhost:8088/order/add ——>路由到
#http://order-service/order/add
8.基于Query请求参数的断言工厂
QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。
- Query=name,zxy #http://localhost:8088/order/add?name=zxy
9.基于路由权重的断言工厂
WeightRoutePredicateFactory:接收一个[组名,权重], 然后对于同一个组内的路由按照权重转发。
gateway:
routes:
- id: weight_route1
uri: host1
predicates:
- Path=/product/**
- Weight=group3, 1
- id: weight_route2
uri: host2
predicates:
# 路径一致,组一致,权重不同
- Path=/product/**
- Weight= group3, 9
六.简单的自定义断言
自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写 apply 方法的逻辑。在 apply 方法中可以通过 exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。
-
必须spring组件 bean
-
类必须加上RoutePredicateFactory作为结尾
-
必须继承AbstractRoutePredicateFactory
-
必须声明静态内部类 声明属性来接收 配置文件中对应的断言的信息
-
需要结合shortcutFieldOrder进行绑定
-
通过apply进行逻辑判断 true就是匹配成功 false匹配失败
ctrl+h 对AbstractRoutePredicateFactory找到任意子类作为模板修改自己的自定义断言
!!!自定义断言类名需要以 RoutePredicateFactory 结尾
@Component
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {
public CheckAuthRoutePredicateFactory() {
super(CheckAuthRoutePredicateFactory.Config.class);
}
public List<String> shortcutFieldOrder() {
//接受config的值
return Arrays.asList("name");
}
public Predicate<ServerWebExchange> apply(CheckAuthRoutePredicateFactory.Config config) {
return new GatewayPredicate() {
public boolean test(ServerWebExchange exchange) {
if(config.getName().equals("zxy")){
return true;
}
return false;
}
};
}
//用于接受配置文件中 断言的信息
@Validated
public static class Config {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
yml配置
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
#gateway
gateway:
#路由规则
routes:
- id: order_route #路由的唯一标识,例如路由到order
uri: lb://order-service #需要转发的地址 lb: 使用nacos中的本地负载均衡策略
predicates:
- Path=/order/**
- CheckAuth=zxy #自定义的简单断言
七.过滤器工厂配置
( GatewayFilter Factories)
1.内置的局部过滤器工厂配置
!!!一共有三十中配置
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
(33条消息) 网关 Spring Cloud Gateway 内置过滤器工厂(超级全30种)_lakernote的博客-CSDN博客
常用的几种:
2.自定义局部过滤器工厂
@Component
public class CheckAuthGatewayFilterFactory
extends AbstractGatewayFilterFactory<CheckAuthGatewayFilterFactory.Config> {
public CheckAuthGatewayFilterFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("value");
}
@Override
public GatewayFilter apply(Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String name=exchange.getRequest().getQueryParams().getFirst("name");
if(StringUtils.isNotBlank(name)){
if(config.getValue().equals(name)){
return chain.filter(exchange);
}
else {
// 返回404
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
return exchange.getResponse().setComplete();
}
}
// 正常请求
return chain.filter(exchange);
}
};
}
public static class Config {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
filters:
#- AddRequestHeader=X-Request-color,red #添加请求头 (请求过程)
- PrefixPath=/mall‐order
#添加前缀http://localhost:8088/order/add——>
#http://localhost:8088/mall‐order/order/add
#- RedirectTo=302,https://www.baidu.com/ #重定向
#- SetStatus=404 #修改状态码
- CheckAuth=xxx #自定义过滤器
3.全局过滤器(Global Filters)配置
局部过滤器和全局过滤器区别:
局部:局部针对某个路由, 需要在路由中进行配置
全局:针对所有路由请求, 一旦定义就会投入使用
GlobalFilter 接口和 GatewayFilter 有一样的接口定义,只不过, GlobalFilter 会作用于所有路由
LoadBalancerClientFilter
LoadBalancerClientFilter 会查看exchange的属性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值(一个URI),如果该值的scheme是 lb,比如:lb://myservice ,它将会使用Spring Cloud的LoadBalancerClient 来将 myservice 解析成实际的host和port,并替换掉 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的内容。
routes:
- id: order_route
uri: lb://order-service #lb: 使用nacos中的本地负载均衡策略
predicates:
- Path=/**
filters:
- PrefixPath=/mall‐order
还可以基于ReactiveLoadBalancerClientFilter用来整合负载均衡器Ribbon的。
还没写
自定义全局过滤器
@Component
public class LogFilter implements GlobalFilter {
Logger log= LoggerFactory.getLogger(this.getClass());
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info(exchange.getRequest().getPath().value());
return chain.filter(exchange);
}
}
八.访问日志和跨域配置
访问日志
要启用 Reactor Netty 访问日志,请设置
-Dreactor.netty.http.server.accessLogEnabled=true
它必须是 Java 系统属性,而不是 Spring Boot 属性。
您可以将日志记录系统配置为具有单独的访问日志文件。以下示例创建一个.logback.xml配置:
<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
<file>access_log.log</file>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
<appender‐ref ref="accessLog" />
</appender>
<logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
<appender‐ref ref="async"/>
</logger>
<!--输出为日志文本(可以搞也可以不搞,建议学习springboot日志)-->
开启日志后:
2023-04-13 23:22:27.946 INFO 18884 --- [ctor-http-nio-2] reactor.netty.http.server.AccessLog : 0:0:0:0:0:0:0:1 - - [13/Apr/2023:23:22:26 +0800] "GET /order/add HTTP/1.1" 200 29 8088 976 ms
跨域配置
方法一(yml配置)
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]': #允许跨域的资源
allowedOrigins: "https://docs.spring.io" #允许跨域的来源url
allowedMethods: #允许跨域的请求方法
- GET
allowedHeaders: '*' #允许跨域的请求头
# 预检请求的缓存时间(秒),即在这个时间段里对于相同的跨域请求不会再预检
maxAge: 180
方法二(java)
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 允许cookies跨域
config.setAllowCredentials(true);
// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedOrigin("*");
// #允许访问的头信息,*表示全部
config.addAllowedHeader("*");
// 预检请求的缓存时间(秒)Long型,即在这个时间段里,对于相同的跨域请求不会再预检了
config.setMaxAge(180L);
//允许的方法 可设置* 即允许全部http请求方法类型
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
九.Gateway整合sentinel
1.导入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--Sentinel整合gateway alibaba2.1之后一个依赖足够-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
2.添加yml配置
sentinel:
transport:
dashboard: 127.0.0.1:8858
控制台实现方式:
Sentinel 1.6.3 引入了网关流控控制台的支持,用户可以直接在 Sentinel 控制台上查看 API Gateway 实时的 route 和自定义 API 分组监控,管理网关规则和 API 分组配置。
从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:
route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId
自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组
十.整合sentinel的详细配置
流控规则(根据路由ID)
1.属性限流Client IP
精确比如:127.0.0.1
2.属性限流Header
3.属性限流URL
4.属性限流Remote Host
5.属性限流 Cookie
降级规则(根据路由ID)
其他规则和sentinel一致
API分组
1.设置API分组
2.API分组流控
和根据路由ID流控规则一致
3.API分组降级
和根据路由ID降级规则一致
自定义流控降级返回
方法一(配置类)
@Configuration
public class GatewayConfig {
@PostConstruct
public void init(){
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
System.out.println(throwable);
HashMap<String,String> map = new HashMap<>();
map.put("code", HttpStatus.TOO_MANY_REQUESTS.toString());
map.put("message","限流了");
//自定义异常处理
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(map));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
}
@Configuration
public class GatewayConfig {
@PostConstruct
public void init(){
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable e) {
Result r = null;
if (e instanceof FlowException) {
r = Result.error(100,"接口限流了");
} else if (e instanceof DegradeException) {
r = Result.error(101,"服务降级了");
} else if (e instanceof ParamFlowException) {
r = Result.error(102,"热点参数限流了");
} else if (e instanceof SystemBlockException) {
r = Result.error(103,"触发系统保护规则了");
} else if (e instanceof AuthorityException) {
r = Result.error(104,"授权规则不通过");
}
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(r));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
}
public class Result<T> {
private Integer code;
private String msg;
private T data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Result(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public Result(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public static Result error(Integer code,String msg){
return new Result(code,msg);
}
}
方法二(yml配置)
#配置sentinel
sentinel:
transport:
dashboard: 127.0.0.1:8080
scg:
fallback: #流控降级规则
mode: response
response-body: "{code:'1002',message:'limit limit'}"
十一.网关高可用
为了保证 Gateway 的高可用性,可以同时启动多个 Gateway 实例进行负载,在 Gateway 的上游使用 Nginx 或者 F5 进行负载转发以达到高可用。
Gateway依赖和yml配置总合
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
sentinel:
transport:
dashboard: 127.0.0.1:8858
scg:
fallback: #流控降级规则 使用配置类更好
mode: response
response-body: "{code:'1002',message:'limit limit'}"
#gateway
gateway:
#路由规则
routes:
- id: order_route #路由的唯一标识,例如路由到order
uri: lb://order-service #需要转发的地址 lb: 使用nacos中的本地负载均衡策略
#(我们直接写服务地址维护十分麻烦,通过nacos使用服务调用)
#断言规则 用于路由规则的匹配
predicates:
- Path=/order‐serv/** #当请求路径满足Path指定的规则时,才进行路由转发
#http://localhost:8088/order‐serv/order/add ——>路由到
#http://order-service/order‐serv/order/add ->filter后
#http://order-service/order/add
#http://localhost:8088/order/add ——>路由到
#http://order-service/order/add
#- After=2027-12-31T23:59:59.789+08:00[Asia/Shanghai]
#- Header=X-Request-Id,\d+ #请求头断言,例如这个:key为X-Request-Id,value为数字
#- Method=GET #请求方法断言
#- Query=name,zxy #http://localhost:8088/order/add?name=zxy
#- CheckAuth=zxy #自定义的简单断言
filters:
- StripPrefix=1 #路由转发之前去掉第一层路径,即/order‐serv/
#- AddRequestHeader=X-Request-color,red #添加请求头 (请求过程)
- PrefixPath=/mall‐order
#添加前缀http://localhost:8088/order/add——>
#http://localhost:8088/mall‐order/order/add
#- RedirectTo=302,https://www.baidu.com/ #重定向
#- SetStatus=404 #修改状态码
- CheckAuth=xxx #自定义过滤器
#- id: stock_route
#gateway
#gateway:
# discovery:
# locator:
# enabled: true #是否启动自动识别nacos服务
globalcors: #跨域配置
cors-configurations:
'[/**]': #允许跨域的资源
allowedOrigins: "https://docs.spring.io" #允许跨域的来源url
allowedMethods: #允许跨域的请求方法
- GET
allowedHeaders: '*' #允许跨域的请求头
# 预检请求的缓存时间(秒),即在这个时间段里对于相同的跨域请求不会再预检
maxAge: 180
依赖
<!‐‐ gateway网关 Spring Cloud开发 ‐‐>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring‐cloud‐starter‐gateway</artifactId>
</dependency>
<!‐‐ gateway网关整合nacos ‐‐>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--Sentinel整合gateway alibaba2.1之后一个依赖足够-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>