当前位置: 代码迷 >> 综合 >> spring-cloud-gateway(1)--->spring-cloud-gateway的基本使用
  详细解决方案

spring-cloud-gateway(1)--->spring-cloud-gateway的基本使用

热度:117   发布时间:2023-10-24 14:37:15.0

1、API网关

     API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。

网关应当具备以下功能:

  • 性能:API高可用,负载均衡,容错机制。
  • 安全:权限身份认证、脱敏,流量清洗,后端签名(保证全链路可信调用),黑名单(非法调用的限制)。
  • 日志:日志记录(spainid,traceid)一旦涉及分布式,全链路跟踪必不可少。
  • 缓存:数据缓存。
  • 监控:记录请求响应数据,api耗时分析,性能监控。
  • 限流:流量控制,错峰流控,可以定义多种限流规则。
  • 灰度:线上灰度部署,可以减小风险。
  • 路由:动态路由规则。

目前,比较流行的网关有:Nginx 、 Kong 、Orange等等,还有微服务网关Zuul 、Spring Cloud Gateway等等

对于 API Gateway,常见的选型有基于 Openresty 的 Kong、基于 Go 的 Tyk 和基于 Java 的 Zuul。这三个选型本身没有什么明显的区别,主要还是看技术栈是否能满足快速应用和二次开发。

 

2、spring-cloud-gateway 模型图:

      

             在使用spring-cloud-gateway的时候,我们一般的做法是构建一个网关微服务,然后在里面配置各种路由信息。

 

3、实战案例:

       3.1、构建一个spring-boot项目引入如下依赖:

        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>

        3.2、项目启动类:

      @SpringBootApplicationpublic class GatewayService {public static void main(String[] args) {SpringApplication.run(GatewayService.class, args);}}

         3.3、配置路由:

                 我们配置一个简单的路由,主要是通过网关服务进行转发到我们的订单服务:

spring:cloud:gateway:routes:- id: orderapi                    #当前路由的iduri: http://localhost:7070      #当前路由转发的目标服务predicates:                     #当前路由的断言列表- Path=/orderapi/**                使用spring-cloud-gateway提供的Path断言filters:                        #当前路由的过滤器列表- StripPrefix=1  #表示在路径匹配的时候会去掉第一级,例如输入http://localhost:6060/orderapi/order/findAll#将会转发到http://localhost:7070/order/findAll#StripPrefix=1的含义就是会去掉/orderapi  如果等于2就会去掉/orderapi/order

         这就是一个简单的路由配置。在spring-cloud-gateway中提供了很多的断言、过滤器的实现,详细可见官网。

 

4、自定义断言:

      在spring-cloud-gateway中提供了很多的断言、过滤器的实现,我们也可以实现自己的断言或者过滤器,接下来我们以实现断言为案例进行讲解。

      我们实现一个断言,这个断言的核心业务是需要检查请求的Header中是否存在accesstoken这个属性,如果存在我们进行请求转发,如果不存在就不进行转发。

       实现的方式也比较简单,只需要实现 AbstractRoutePredicateFactory 这个接口即可,只是有一下约束而已,固定为断言Name + "RoutePredicateFactory"字符,然后配置使用的时候使用断言名称配置即可。

/*** 自定义断言,类名格式断言名称+ “RoutePredicateFactory”*/
@Component
public class AuthRoutePredicateFactory extends AbstractRoutePredicateFactory<AuthRoutePredicateFactory.Config> {public AuthRoutePredicateFactory() {super(Config.class);}//定义配置值的顺序@Overridepublic List <String> shortcutFieldOrder() {return Arrays.asList("headeKey");}@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return new GatewayPredicate() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {HttpHeaders headers = serverWebExchange.getRequest().getHeaders();List <String> strings = headers.get(config.getHeadeKey());if (CollectionUtils.isEmpty(strings)){return false;}else {return true;}}};}@Validatedpublic static class Config {@NotEmptyprivate String headeKey;public Config() {}public String getHeadeKey() {return headeKey;}public void setHeadeKey(String headeKey) {this.headeKey = headeKey;}}
}

       自定义断言的配置方式:

spring:cloud:gateway:routes:     - id: costomer_predicateuri: http://www.baidu.compredicates:- Path=/customer/predicate/**- Auth=accesstoken     //自定义的断言名称,断言中的配置实例的headeKey=accesstokenfilters:- StripPrefix=2

 

5、网关层使用hystrix进行断路保护

     5.1、引入hystrix的如下依赖:

      <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>

   5.2、使用spring-cloud-gateway提供的Hystrix相关的过滤器,配置如下:

spring:cloud:gateway:routes:
#常规断言的使用- id: orderapiuri: http://localhost:7070predicates:- Path=/orderapi/**filters:- StripPrefix=1  #表示在路径匹配的时候会去掉第一级,例如输入http://localhost:6060/orderapi/order/findAll#将会转发到http://localhost:7070/order/findAll#StripPrefix=1的含义就是会去掉/orderapi  如果等于2就会去掉/orderapi/order配置hystrix过滤器进行断路保护            - name: Hystrixargs:name: fallbackcmd       配置构建的hystrixCommand的id=fallbackcmdfallbackUri: forward:http://localhost:6060/fallback#fallbackUri: forward:/orderapi/order/mock  #转发请求到http://localhost:6060//orderapi/order/mock#因此也会调到http://localhost:7070/order/mock, 也可以在#网关服务中定义controller 进行转发过去。可对id=fallbackcmd进行属性配置
hystrix:command:fallbackcmd:execution:isolation:thread:timeoutInMilliseconds: 1000

 

6、网关层使用redis进行网关层的限流

      6.1、先引入redis相关依赖如下:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis-reactive</artifactId></dependency>

       6.2、实现限流的key解析器,作用就是定义限流的规则,例如按照请求参数中的某个值进行限流,我们就以请求中的userId进行限流来实现一个key解析器:

    @BeanKeyResolver userKeyResolver() {return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));}

       6.3、配置redis:   

 spring:  redis:host: localhostport: 6379

      6.4、给某个路由配置限流:

spring:application:name: gateway-servercloud:gateway:routes:
#常规断言的使用- id: orderapiuri: http://localhost:7070predicates:- Path=/orderapi/**filters:- StripPrefix=1  #表示在路径匹配的时候会去掉第一级,例如输入http://localhost:6060/orderapi/order/findAll#将会转发到http://localhost:7070/order/findAll#StripPrefix=1的含义就是会去掉/orderapi  如果等于2就会去掉/orderapi/order- name: Hystrixargs:name: fallbackcmdfallbackUri: forward:http://localhost:6060/fallback
#            fallbackUri: forward:/orderapi/order/mock  #转发请求到http://localhost:6060//orderapi/order/mock#因此也会调到http://localhost:7070/order/mock, 也可以在#网关服务中定义controller 进行转发过去。- name: RequestRateLimiterargs:# redis-rate-limiter是基于令牌桶来实现的#rate-limiter: "#{@redisRateLimiter}"       #指定限流器的beanName, 如果我们配置了redis-rate-limiter.*#redis-rate-limiter: "#{@redisRateLimiter}"  redisRateLimiter 这个bean也是#spring-cloud-gateway自动装配的,当然如果我们自定义限流器的话,我们是需要配置#自定义的限流器beanName的。redis-rate-limiter.replenishRate: 10    #往令牌桶里放令牌的速率,3 表示每秒放3个令牌进去redis-rate-limiter.burstCapacity: 20    #令牌通中最多放多少个令牌,这个值就约等于每秒最大请求数。redis-rate-limiter.requestedTokens: 1  #每次请求消耗多少个令牌key-resolver: "#{@userKeyResolver}"        #限流键的解析器,此处配置的是实现了KeyResolver的bean userKeyResolver,#例如userKeyResolver从请求中获取有查询参数的user的入参,例如 user=1#userId=1  跟userId=2 的令牌通是隔离的,不通用的。

 

7、整合服务注册与发现在转发服务按照服务名称进行负载均衡的配置:

      我们部署微服务的时候基本上都是集群部署,并且将服务信息注册到服务注册中心,那么在网关层面就需要进行服务发现,然后进行转发的负载均衡。

     7.1、在网关服务中映入eureka-clientd 的相关依赖:

        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>

     7.2、配置eureka-server信息:

eureka:client:service-url:defaultZone: http://localhost:9090/eureka

    7.3、配置激活器网关的服务发现定位器:

spring:cloud:gateway:discovery:locator:enabled: truelower-case-service-id: true

     7.4、配置路由route的uri使其能够进行负载均衡:

spring:application:name: gateway-servercloud:gateway:routes:- id: userapiuri: lb://user-service    //使用lb://服务名称的方式predicates:- Path=/userapi/**filters:- StripPrefix=1

      

8、自定义全局过滤器

      在spring-cloud-gateway中有两种类型的filter,一种的局部的filter,只有配置到路由中的时候才生效,还有就是全局的filter,全局的不需要单独配置给某个route,而是所有的route都生效,接下来我们来实现一个全局的filter,这个filter的业务就是请求前后进行日志输出:这里的实现是跟reactor的知识点有关,需要有一定的响应式编程的基础知识。

/*** 全局过滤器是不需单独给predicate 进行配置,因为默认就是给所有的predicate配置上。*/
@Component
public class CustomerLogGlobalFilter implements GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("【CustomerLogGlobalFilter】 pre log 。 。 。");Mono <Void> mono = chain.filter(exchange).then(Mono.fromRunnable(() -> {MultiValueMap <String, HttpCookie> cookies = exchange.getRequest().getCookies();System.out.println("【CustomerLogGlobalFilter】 post log 。 。 。" + cookies.toSingleValueMap());}));return mono;}
}

      

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

       

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  相关解决方案