赞
踩
Gateway 是在 Spring 生态系统之上构建的 API 网关服务,基于Spring 5、 Spring Boot 2 和 Project Reactor等技术。
Gateway 旨在提供一 种简单而有效的方式来对 API 进行路由,以及提供一 些强大的过滤器功能, 例如:熔断、限流、重试等
Spring Cloud Gateway 使用的 Webflux 中的 reactor-netty 响应式编程组件,底层使用了Netty通讯框架。
传统的 Web 框架,比如说: struts2, springmvc 等都是基于 Servlet API 与 Servlet 容器基础之上运行的。但是在 Servlet3.1 之后有了异步非阻塞的支持。而 WebFlux 是一个 典型非阻塞异步的框架,它的核心是基于 Reactor 的相关 API 实现的。相对于传统的 web 框架来说,它可以运行在诸如 Netty、Undertow 及支持Servlet3.1 的容器上。非阻塞式+函数式编程(Spring5 必须使用 java8)Spring WebFlux是Spring 5.0引入的新的响应式框架,区别于Spring MVC,它不需要依赖 Servlet API,它是完全异步非阻塞的,并且基于 Reactor 来实现响应式流规范。
1. Route(路由)
路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为 true 则匹配该路由
2. Predicate(断言)
参考的是 Java8 的 java.util.function.Predicate,开发人员可以匹配 HTTP 请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
3. Filter(过滤)
指的是 Spring 框架中 GatewayFilter 的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前( "pre" )或之后( "post")执行业务逻辑。Filter 在 "pre" 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等。在 “post” 类型的过滤器中可以做响应内容、响应头的修改,日志的输出, 流量监控等有着非常重要的作用。
核心逻辑:路由转发+执行过滤器链
创建 module: cloud-gateway-gateway9527
pom:
- <!--新增gateway-->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-gateway</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
YML:
- server:
- port: 9527
- spring:
- application:
- name: cloud-gateway
- cloud:
- gateway:
- routes:
- - id: payment_routh # 路由的ID
- uri: http://localhost:8001 # 匹配后提供服务的路由地址
- predicates:
- - Path=/payment/get/** # 断言,路径相匹配的进行路由
-
- - id: payment_routh2
- uri: http://localhost:8001
- predicates:
- - Path=/payment/lb/** #断言,路径相匹配的进行路由
-
-
- eureka:
- instance:
- hostname: cloud-gateway-service
- client:
- service-url:
- register-with-eureka: true
- fetch-registry: true
- defaultZone: http://eureka7001.com:7001/eureka
启动类:
- @SpringBootApplication
- @EnableEurekaClient
- public class GateWayMain9527 {
- public static void main(String[] args){
- SpringApplication.run(GateWayMain9527.class,args);
- }
- }
测试:
1. 在配置文件 yml 中配置(同上)
2. 代码中注入 RouteLocator 的 Bean
- @Configuration
- public class GateWayConfig {
- @Bean
- public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
- RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
- routes.route("path_rote_zth", r -> r.path("/payment/lb").uri("http://localhost:8001")).build();
- return routes.build();
- }
- }
默认情况下 Gateway 会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能。
YML;
- server:
- port: 9527
- spring:
- application:
- name: cloud-gateway
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
- routes:
- - id: payment_routh # 路由的ID
- uri: lb://CLOUD-PAYMENT-SERVICE
- predicates:
- - Path=/payment/get/** # 断言,路径相匹配的进行路由
- - id: payment_routh2
- uri: lb://CLOUD-PAYMENT-SERVICE
- predicates:
- - Path=/payment/lb/**
-
- eureka:
- instance:
- hostname: cloud-gateway-service
- client:
- service-url:
- register-with-eureka: true
- fetch-registry: true
- defaultZone: http://eureka7001.com:7001/eureka
测试:
Spring Cloud Gateway 将路由匹配作为 Spring WebFlux HandlerMapping 基础架构的一部分。
Spring Cloud Gateway 包括许多内置的 Route Predicate 工厂。所有这些 Predicate 都与 HTTP 请求的不同属性匹配。 多个Route Predicate 工厂可以进行组合
Spring Cloud Gateway 创建 Route 对象时,使用 RoutePredicateFactory 创建 Predicate 对象,Predicate 对象可以赋值给
Route。Spring Cloud Gateway包含许多内置的Route Predicate Factories。
After Route Predicate Factory:
此谓词匹配当前日期时间之后发生的请求。
yml:
- spring:
- application:
- name: cloud-gateway
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
- routes:
- - id: payment_routh # 路由的ID
- uri: lb://CLOUD-PAYMENT-SERVICE
- predicates:
- - After=2020-07-08T12:44:53.402+08:00[Asia/Shanghai]
时间未到请求:
时间到了请求:
【注】获取时间串
- ZonedDateTime zonedDateTime = ZonedDateTime.now();
- System.out.println(zonedDateTime);
Cookie Route Predicate:
Cookie Route Predicate 需要两个参数, 一个是 Cookie name ,一个是正则表达式。路由规则会通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。
YML:
- spring:
- application:
- name: cloud-gateway
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
- routes:
- - id: payment_routh # 路由的ID
- uri: lb://CLOUD-PAYMENT-SERVICE
- predicates:
- - Cookie=name,zth
测试:
所有 Route Predicate:
- spring:
- application:
- name: cloud-gateway
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
- routes:
- - id: payment_routh # 路由的ID
- uri: lb://CLOUD-PAYMENT-SERVICE
- predicates:
- - Path=/payment/lb/**
- #- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
- #- Cookie=name,zth
- #- Header=X-Request-Id, \d+ # 请求头中要有 X-Request-Id 属性并且值为整数的正则表达式
- #- Host=**.zth.com
- #- Method=GET
- #- Query=username, \d+ # 要有参数名称并且是正整数才能路由
路由过滤器可用于修改进入的 HTTP 请求和返回的 HTTP 响应,路由过滤器只能指定路由进行使用。
Spring Cloud Gateway内置了多种路由过滤器,他们都由GatewayFilter 的工厂 类来产生。
过滤器类型:
Spring Cloud Gateway 的 Filter 从作用范围可分为另外两种 GatewayFilter 与 GlobalFilter。
GatewayFilter :应用到单个路由或者一个分组的路由上。
GlobalFilter :应用到所有的路由上。
示例:添加响应头
YML:
- spring:
- application:
- name: cloud-gateway
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
- routes:
- - id: payment_routh # 路由的ID
- uri: lb://CLOUD-PAYMENT-SERVICE
- predicates:
- - Path=/**
- filters:
- - AddResponseHeader=X-Response-Red, Blue
测试:
限流算法(传送门)
pom:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
配置类:
- @Configuration
- public class RequestRateLimiterConfig {
- @Bean
- @Primary
- KeyResolver apiKeyResolver() {
- //按URL限流,即以每秒内请求数按URL分组统计,超出限流的url请求都将返回429状态
- return exchange -> Mono.just(exchange.getRequest().getPath().toString());
- }
-
- @Bean
- KeyResolver userKeyResolver() {
- //按用户限流
- return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
- }
-
- @Bean
- KeyResolver ipKeyResolver() {
- //按IP来限流
- return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
- }
- }
YML:
- server:
- port: 9527
- spring:
- redis:
- host: localhost
- port: 6379
- database: 0
- password: redis
- application:
- name: cloud-gateway
- cloud:
- gateway:
- routes:
- - id: payment_routh # 路由的ID
- uri: http://localhost:8001
- predicates:
- - Path=/**
- filters:
- - name: RequestRateLimiter
- args:
- # 令牌桶每秒填充平均速率,即行等价于允许用户每秒处理多少个请求平均数
- redis-rate-limiter.replenishRate: 1
- # 令牌桶的容量,允许在一秒钟内完成的最大请求数
- redis-rate-limiter.burstCapacity: 3
- # 用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取
- key-resolver: "#{@ipKeyResolver}"
-
- eureka:
- instance:
- hostname: cloud-gateway-service
- client:
- service-url:
- register-with-eureka: true
- fetch-registry: true
- defaultZone: http://eureka7001.com:7001/eureka
-
测试:
redis:
jemert 压测:
全局过滤器(GlobalFilter)作用于所有路由,Spring Cloud Gateway 定义了Global Filter接口,用户可以自定义 Global Filter。通过全局过滤器可以实现对权限的统一校验,安全性验证等功能。
- @Component
- @Slf4j
- public class MyLogGateWayFilter implements GlobalFilter, Ordered {
- @Override
- public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
- log.info("***********come in MyLogGateWayFilter:"+new Date());
-
- String name = exchange.getRequest().getQueryParams().getFirst("name");
- if (null == name){
- log.info("***********用户名为空********");
- exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
- return exchange.getResponse().setComplete();
- }
- return chain.filter(exchange);
- }
-
- @Override
- public int getOrder() {
- return 0;
- }
- }
测试:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。