SpringCloudAlibaba随笔目录
二、SpringCloudAlibaba项目之Nacos搭建及服务注册
三、SpringCloudAlibaba项目之生产者与消费者
四、SpringCloudAlibaba项目之Ribbon负载均衡
五、SpringCloudAlibaba项目之OpenFeign远程调用
六、SpringCloudAlibaba项目之Nacos-config配置中心
七、SpringCloudAlibaba项目之Sentinel流量控制
八、SpringCloudAlibaba项目之Seata分布式事务
九、SpringCloudAlibaba项目之GateWay网关
十、SpringCloudAlibaba项目之SkyWalking链路追踪
SpringCloudAlibaba项目之GateWay网关
1、什么是API 网关
(1)定义
网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。
(2)职能
(3)分类与功能
2、GateWay
(1)简介
Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。
github:https://github.com/apex/gateway
(2)为什么使用Gateway
Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。
比如内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。
比如区分了一般的 Filter 和全局 Filter,内置了 20 种 Filter 和 9 种全局 Filter,也都可以直接用。当然自定义 Filter 也非常方便。
(3)概念
3、快速使用
pom.xml依赖
<!-- nacos 服务注册发现(客户端)依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- gateway 网关依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
application.yml(推荐使用yaml格式)
# 应用服务 WEB 访问端口
server:
port: 8090
spring:
application:
name: service-gateway # 应用名称
cloud:
# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
# Nacos认证信息
nacos:
discovery:
username: nacos
password: nacos
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
server-addr: 127.0.0.1:8848
namespace: public # 注册到 nacos 的指定 namespace,默认为 public
# gateway 配置
gateway:
# 路由规则
routes:
- id: order_route # 路由的唯一标识,路由到order
uri: lb://service-openfeign # 需要转发的地址 lb:使用nacos本地的负载均衡策略
# 断言规则 用于路由规则的匹配
predicates:
- Path=/service-order/**
# 过滤器
filters:
- StripPrefix=1 #转发之前去掉第一层路由
注意:yaml格式注意每个字段对应的位置,否则会出问题
访问地址:http://127.0.0.1:8090/service-order/order/addOrder
4、路由断言工厂
(1)内置路由断言工厂
4.1、After Route Predicate Factory
After Route Predicate Factory 中获取一个UTC时间格式的参数, 当请求的当前时间在配置的UTC时间之后,则会成功匹配,否则不能成功匹配。
application.yml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://xxx.com
predicates:
- After=2021-01-20T17:42:47.789-07:00[Asia/Shanghai]
该路由匹配所有UTC时间Jan 20, 2021 17:42后的请求,并且路由到uri:http://xxx.com
4.2、Before Route Predicate Factory
Before Route Predicate Factory 中获取一个UTC时间格式的参数, 当请求的当前时间在配置的UTC时间之前,则会成功匹配,否则不能成功匹配。
application.yml
spring:
cloud:
gateway:
routes:
- id: before_route
uri: http://xxx.com
predicates:
- Before=2021-01-20T17:42:47.789-07:00[Aisa/Shanghai]
该路由匹配所有UTC时间Jan 20, 2021 17:42之前的请求,并且路由到uri:http://xxx.com
4.3、Between Route Predicate Factory
Between Route Predicate Factory 中获取一个UTC时间格式的参数, 当请求的当前时间在配置的UTC时间之间,则会成功匹配,否则不能成功匹配。
application.yml
spring: cloud: gateway: routes: - id: between_route uri: http://xxx.com predicates: - Between=2021-01-20T17:42:47.789-07:00[Aisa/Shanghai], 2021-01-21T17:42:47.789-07:00[Aisa/Shanghai]
如果在这个区间,就可以正常匹配路由并访问。
4.4、Cookie Route Predicate Factory
Cookie Route Predicate Factory 会取两个参数(Header中以“Cookie”命名的名称,对应的Key和Value)。当请求携带的cookie和Cookie断言工厂配置的一致,则路由匹配成功,否则匹配失败。
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: http://xxx.com
predicates:
- Cookie=chocolate, ch.p
这个路由将匹配cookie中存在chocolate=ch.p
的请求
4.5、Header Route Predicate Factory
Header Route Predicate Factory 根据配置的路由Header信息进行断言匹配路由,匹配成功进行转发,否则不进行转发。application.yml
spring:
cloud:
gateway:
routes:
- id: header_route
uri: http://xxx.com
predicates:
- Header=X-Request-Id, \d+
这个路由将匹配请求头中包含X-Request-Id
且值为一个或者多个数字的请求。
4.6、Host Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://xxx.com
predicates:
- Host=**.somehost.org,**.anotherhost.org
这个路由将匹配请求的Host头为www.somehost.org or beta.somehost.org or www.anotherhost.org.
4.7、Method Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: method_route
uri: http://xxx.com
predicates:
- Method=GET
这个路由匹配HttpMethod为Get的请求。
4.8、Path Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://xxx.com
predicates:
- Path=/foo/{segment},/bar/{segment}
如有请求地址如 /foo/1
or /foo/bar
or /bar/baz
,那么将匹配该路由。
4.9、Query Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: query_route
uri: http://xxx.com
predicates:
- Query=foo,baz
当前路由将匹配路径参数包含foo=baz的请求。
4.10、RemoteAddr Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: http://xxx.com
predicates:
- RemoteAddr=192.168.1.1/24
请求发起端ip为192.168.1.1~192.168.1.255的请求。
(2)自定义路由断言工厂
自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写 apply 方法的逻辑和shortcutFieldOrder方法。在 apply 方法中可以通过 exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。apply 方法的参数是自定义的配置类,在使用的时候配置参数,在 apply 方法中直接获取使用。命名需要以 RoutePredicateFactory 结尾,比如 CheckAuthRoutePredicateFactory,那么在使用的时候 CheckAuth 就是这个路由断言工厂的名称。
CheckAuthRoutePredicateFactory
/** * 自定义路由断言工厂 */ @Component public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> { public CheckAuthRoutePredicateFactory() { super(Config.class); System.out.println("Loaded RoutePredicateFactory [CheckAuth]"); } @Override public List<String> shortcutFieldOrder() { return Arrays.asList("name"); } /** * 自定义断言规则 * @param config * @return */ @Override public Predicate<ServerWebExchange> apply(Config config) { System.out.println("Name===>:" + config.getName()); return exchange -> { if (config.getName().equals("qt")) { return true; } return false; }; } //配置一个内部类 public static class Config { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } } }
application.yml中添加路由配置
spring:
cloud:
# gateway 配置
gateway:
# 路由规则
routes:
- id: order_route # 路由的唯一标识,路由到order
uri: lb://service-openfeign # 调用接口的服务名,需要转发的地址 lb:使用nacos本地的负载均衡策略
# 断言规则 用于路由规则的匹配
predicates:
- Path=/service-order/**
- CheckAuth=qt
# 过滤器
filters:
- StripPrefix=1 #转发之前去掉第一层路由
5、过滤器
Spring Cloud Gateway除了具备请求路由功能之外,也支持对请求的过滤。通过Zuul网关类似,也是通过过滤器的形式来实现的。
(1) 过滤器的生命周期
Spring Cloud Gateway 的 Filter 的生命周期不像 Zuul 的那么丰富,它只有两个:“pre” 和 “post”。
PRE : 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
POST :这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
( 2) 过滤器类型
Spring Cloud Gateway 的 Filter 从作用范围可分为两种GatewayFilter 与 GlobalFilter。
GatewayFilter (局部过滤器):应用到单个路由或者一个分组的路由上。
GlobalFilter (全局过滤器):应用到所有的路由上。
(3)局部过滤器
局部过滤器(GatewayFilter),是针对单个路由的过滤器。可以对访问的URL过滤,进行切面处理。在Spring Cloud Gateway中通过GatewayFilter的形式内置了很多不同类型的局部过滤器。这里简单将Spring Cloud Gateway内置的所有过滤器工厂整理成了一张表格,虽然不是很详细,但能作为速览使用。如下:
每个过滤器工厂都对应一个实现类,并且这些类的名称必须以 GatewayFilterFactory 结尾,这是Spring Cloud Gateway的一个约定,例如 AddRequestHeader 对应的实现类为AddRequestHeaderGatewayFilterFactory 。对于这些过滤器的使用方式可以参考官方文档。
(4)全局过滤器
全局过滤器(GlobalFilter)作用于所有路由,Spring Cloud Gateway 定义了Global Filter接口,用户可以自定义实现自己的Global Filter。通过全局过滤器可以实现对权限的统一校验,安全性验证等功能,并且全局过滤器也是程序员使用比较多的过滤器。
Spring Cloud Gateway内部也是通过一系列的内置全局过滤器对整个路由转发进行处理如下:
下面的我们自定义一个GlobalFilter,去校验所有请求的请求参数中是否包含“token”,如何不包含请求参数“token”则不转发路由,否则执行正常的逻辑。
/** * 自定义一个全局过滤器 * 实现 globalfilter , ordered接口 */ @Component public class LoginFilter implements GlobalFilter,Ordered { /** * 执行过滤器中的业务逻辑 * 对请求参数中的access-token进行判断 * 如果存在此参数:代表已经认证成功 * 如果不存在此参数 : 认证失败. * ServerWebExchange : 相当于请求和响应的上下文(zuul中的RequestContext) */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("执行了自定义的全局过滤器"); //1.获取请求参数access-token String token = exchange.getRequest().getQueryParams().getFirst("access-token"); //2.判断是否存在 if(token == null) { //3.如果不存在 : 认证失败 System.out.println("没有登录"); exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); //请求结束 } //4.如果存在,继续执行 return chain.filter(exchange); //继续向下执行 } /** * 指定过滤器的执行顺序 , 返回值越小,执行优先级越高 */ @Override public int getOrder() { return 0; } }
参考链接:https://www.cnblogs.com/dalianpai/p/12288884.html
6、跨域处理
gateway配置跨域处理有两种方法,配置文件application.yml和配置类进行配置。
(1)application.yml
spring:
cloud:
gateway:
globalcors:
# 全局允许跨域访问
cors-configurations:
'[/**]':
allow-credentials: true
allowed-origins: "*"
allowed-headers: "*"
allowed-methods:
- OPTIONS
- GET
- POST
- PUT
- DELETE
(2)配置类配置
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.reactive.CorsWebFilter; import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource; import org.springframework.web.util.pattern.PathPatternParser; @Configuration public class CorsConfig { @Bean public CorsWebFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser()); source.registerCorsConfiguration("/**", buildConfig()); return new CorsWebFilter(source); } private CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); //在生产环境上最好指定域名,以免产生跨域安全问题 corsConfiguration.addAllowedOrigin("*"); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); return corsConfiguration; } }
7、整合sentinel流控降级