• springcloud一篇搞定GateWay


    SpringCloud GateWay简介

    SpringCloud Gateway 是 Spring Cloud 的一个全新项目,基于 Spring 5.0+Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

    SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 1.x非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。

    Spring Cloud Gateway的目标提供统一的路由方式且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。

    SpringCloud GateWay基本组件

    1. Route(路由)
    2. Predicate(断言)
    3. Filter(过滤器)

    Route(路由)

    路由是构建网关的基本模块,它由路由ID,需转发到目标微服务URI,以及一系列的Predicate(断言)和Filter(过滤)组成,如果请求符合Predicate,则匹配该路由,按该路由来处理请求

    Predicate(断言)

    断言说简单点,就是请求匹配条件。断言是定义匹配条件,如果请求符合条件,则该请求匹配断言所属的路由

    Filter(过滤器)

    在SpringCloud GateWay这里的Filter的使用场景是:当请求匹配了某个路由后,需要转发到某个微服务之前或之后做一些事情

    image

    SpringCloud GateWay基本使用

    SpringCloud GateWay是以微服务模块作为载体的(也会注册到注册中心上),需要创建一个maven项目作为微服务启动。关于pom.yml、主启动省略,主要说下application.yml的配置,如下:

    server:
      port: 9527
    
    spring:
      application:
        name: cloud-gateway
      cloud:
        gateway:
          routes:
            - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
              uri: http://localhost:8001          #匹配后提供服务的路由地址
              predicates:
                - Path=/payment/get/**         # 断言,路径相匹配的进行路由
    
            - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
              uri: http://localhost:8001          #匹配后提供服务的路由地址
              predicates:
                - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
    

    上面gateway的配置大致说明下:有两个路由,分别是payment_routh和payment_routh2;以payment_routh为例,如果请求是匹配predicates的path,则由该路由进行处理并转发到http://localhost:8001

    总结

    上面的是基本的gateway配置,不过还存在问题:实际项目中某个微服务是作为集群来部署的,因此不能只写死一台服务器的地址,需要负载均衡转发到相同服务但不同实例上。下面则是动态路由的实现方式,能够解决此问题

    SpringCloud GateWay之动态路由

    动态路由只是uri发生了变化,如下:

    server:
      port: 9527
    
    spring:
      application:
        name: cloud-gateway
      cloud:
        gateway:
          routes:
            - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
              uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
              predicates:
                - Path=/payment/get/**         # 断言,路径相匹配的进行路由
    
            - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
              uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
              predicates:
                - Path=/payment/lb/**     # 断言,路径相匹配的进行路由
    

    uri配置为: lb://服务名

    SpringCloud GateWay之Predicate(断言)详细配置

    上面示例的Predicate,只演示了path,这只是匹配条件之一,还有其他匹配条件,如下:
    image
    下面就一些例子,如下:

    spring:
      application:
        name: cloud-gateway
      cloud:
        gateway:
          routes:
            - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
              uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
              predicates:
                - Path=/payment/get/**         # 断言,路径相匹配的进行路由
                - After=2020-02-05T15:10:03.685+08:00[Asia/Shanghai]
                - Before=2020-02-05T15:10:03.685+08:00[Asia/Shanghai]
                - Cookie=username,zzyy
                - Host=**.atguigu.com
                - Query=username, \d+  # 要有参数名username并且值还要是整数才能路由
                - Method=GET
    

    上面的例子表示请求必须:请求的时间在before时间之前,after时间之后,携带key为username,value为zzyy的Cookie,客户端域名需要匹配**.atguigu.com,请求参数中得有username,且值为正整数,请求方式为get。满足上述的条件,此断言才为true,才匹配此路由

    SpringCloud GateWay之Filter(过滤器))详细使用

    在SpringCloud GateWay的Filter分为:GatewayFilter 和 GlobalFilter;

    1. GatewayFilter只针对指定的路由生效。
    2. GlobalFilter对全部路由生效。

    GatewayFilter示例

    server:
      port: 9588
    
    spring:
      application:
        name: cloud-gateway
      cloud:
        gateway:
          discovery:
            locator:
              enabled: true #开启从注册中心动态创建路由的功能
              lower-case-service-id: true #使用小写服务名,默认是大写
          routes:
            - id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
              uri: lb://cloud-provider-payment #匹配后的目标服务地址,供服务的路由地址
              #uri: http://localhost:8001 #匹配后提供服务的路由地址
              filters:
                - AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的请求头加上一对请求头,名称为X-Request-Id值为1024
              predicates:
                - Path=/paymentInfo/**        # 断言,路径相匹配的进行路由
                - Method=GET,POST
    

    当请求匹配了payment_routh路由,就会执行AddRequestParameter这个过滤器进行过滤

    GlobalFilter示例

    @Component //必须加,必须加,必须加
    @Slf4j
    public class MyLogGateWayFilter implements GlobalFilter, Ordered
    {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            log.info("time:"+new Date()+"\t 执行了自定义的全局过滤器: "+"MyLogGateWayFilter"+"hello");
    
            String uname = exchange.getRequest().getQueryParams().getFirst("uname");
            if (uname == null) {
                System.out.println("****用户名为null,无法登录");
                exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                return exchange.getResponse().setComplete();
            }
            return chain.filter(exchange);
        }
    
        @Override
        //指定过滤器在过滤器的执行顺序,数值越小执行顺序越优先
        public int getOrder()
        {
            return 0;
        }
    }
    

    统一鉴权示例:

    @Component //必须加,必须加,必须加
    @Slf4j
    public class AccessGlobalFilter implements GlobalFilter, Ordered {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            String token = exchange.getRequest().getQueryParams().getFirst("token");
    
            if(StringUtils.isEmpty(token)){
                log.info("当前请求Token为空!");
    
                ServerHttpResponse response = exchange.getResponse();
    
                response.getHeaders().add("Content-Type", "application/json;charset=utf-8");
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
    
                return response.setComplete();
            }
    
            log.info("tolen is ok");
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return 1;
        }
    }
    

    不管请求匹配了哪个路由,都会执行gateway全局的过滤器。

    总结

    实际开发,GlobalFilter用的比较多,常用的使用场景是:全局日志,跨域处理,统一鉴权...

  • 相关阅读:
    epoll精髓 C++ 技术中心 C++博客
    【找茬】split string 力为的技术博客 C++博客
    不谈技术~蛇年,我回来了!
    不说技术~希望所有人都好好的
    DDD~充血模型和失血模型
    基础才是重中之重~何为原子化操作
    DDD~概念中的DDD
    策略模式
    windows句柄和消息技术
    观察者模式2(observer)
  • 原文地址:https://www.cnblogs.com/ibcdwx/p/16112582.html
Copyright © 2020-2023  润新知