• SpringCloud(四)GateWay网关


    GateWay网关

    概述简介

    Gateway是在 Spring生态系统之上构建的AP网关服务,基于 Spring5, Spring Boot2和 Project Reactor等技术。
    Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试
    官网地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/

    SpringCloud Gateway是 Spring Cloud的个全新项目,基于 Spring5.0+ Spring Boot2.0和 Project Reactor等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的API路由管理方式
    SpringCloud Gateway作为 Spring Cloud生态系统中的网关,目标是替代zuul,在 Spring Cloud2.0以上版本中,没有对新版本的zuul2.0以上最新高性能版本进行集成,仍然还是使用的zuul1.×非 Reactor模式的老版本。Spring Cloud Gateway使用的 Webflux中的 reactor-netty响应式编程组件,底层使用了 Netty通讯框架
    Spring Cloud Gateway的目标提供统-的路由方式且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流

    主要特点

    作用:反向代理,鉴权,流量控制,熔断,日志监控

    • 基于 Spring Framework5, Project Reactor和 Spring Boot2.0进行构建
    • 动态路由:能够匹配任何请求属性
    • 可以对路由指定 Predicate(断言)和 Filter(过滤器)
    • 集成 Hystrix的断路器功能
    • 集成 Spring Cloud服务发现功能
    • 请求限流功能
    • 支持路径重写

    三大核心概念

    Route(路由)
    路由是构建网关的基本模块,它由 ID,目标URI,一系列的断言和过滤器组成,如果断言为 true 则匹配该路由
    Predicate(断言)
    开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
    Filter(过滤)
    指的是 Spring框架中 Gateway Filter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改
    web请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制,predicate就是我们的匹配条件,而 Filter ,就可以理解为个无所不能的拦截器有了这两个元素,再加上目标 uri 就可以实现一个具体的路由了

    客户端向 Spring Cloud Gateway 发出请求,然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web handler,Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回,过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前("pre")或之后("post")执行业务逻辑
    Filter在"pre"类型的过滤器可以做参数校验、权限校验、流量监控、日志输岀、协议转换等,在"post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用

    路由配置

    1. 创建一个新的 module
    2. 导入 GateWay 依赖
    <!-- Gateway -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
        <version>2.2.2.RELEASE</version>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-webflux</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
    1. 配置路由映射
    • 第一种配置方式:在配置文件 yml 中配置
    server:
      port: 9527
    
    spring:
      application:
        name: GateWay-Service
      cloud:
        gateway:
          routes:
            # 路由的 ID,没有固定规则但要求唯一,建议配合服务名
            - id: payment-route1
            # 匹配后提供服务的路由地址
              uri: http://localhost:8001
            # 断言,路径相匹配的进行路由
            # 配置服务端的方法路径
              predicates:
                - Path=/payment/query/**
    
            - id: payment-route2
              uri: http://localhost:8001
              predicates:
                - Path=/payment/discovery/**
    
    # Eureka
    eureka:
      client:
        # 表示是否将自己注册到 EurekaServer
        register-with-eureka: true
        # 是否从 EurekaServer 抓取已有的注册信息
        # 单节点无所谓,集群必须设置为 true 才能配合 ribbon 使用
        fetch-registry: true
        service-url:
          # 单机版
          # defaultZone: http://localhost:7001/eureka/
          # 集群版
          defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka
      instance:
        hostname: GateWay-Service
    

    • 第二种配置方式:自定义配置文件
    @Configuration
    public class GateConfig {
    
        /**
         * 测试通过网关 跳转到 百度新闻 的页面 http://news.baidu.com/guonei
         * 配置了一个 id 为 payment-route3 的路由规则
         * 当访问地址为 http://localhost:9527/guonei 会自动转发到 http://news.baidu.com/guonei
         * @param routeLocatorBuilder
         * @return
         */
        @Bean
        public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder){
            return routeLocatorBuilder.routes()
                    .route( "payment-route3",r -> {
                        return r.path("/guonei")
                                .uri("http://news.baidu.com/guonei");
                    })
                    .build();
        }
    }
    

    动态路由

    默认情况下 Gateway会根据注册中心注册的服务列表,以注册中心上微服名为路径创建动态路由进行转发,从而实现动态路由的功能
    配置 yml 配置文件
    需要注意的是 uri 的协议为lb,表示启用 Gateway的负载均衡功能
    lb://service Name 是spring cloud gateway在微服务中自动为我们创建的负载均衡uri

    spring:
      application:
        name: GateWay-Service
      cloud:
        gateway:
          discovery:
            locator:
              # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
              enabled: true
          routes:
            # 路由的 ID,没有固定规则但要求唯一,建议配合服务名
            - id: payment-route1
            # 匹配后提供服务的路由地址
            # uri: http://localhost:8001 不能写死
            # 匹配 服务端 的路由地址,就是微服务名
              uri: lb://provider-payment-service
            # 断言,路径相匹配的进行路由
            # 配置服务端的方法路径
              predicates:
                - Path=/payment/lb/**
    
            - id: payment-route2
              uri: lb://provider-payment-service
              predicates:
                - Path=/payment/query/**
    

    开启两个服务端8001和8002
    实现了动态路由,可以测试到此时端口可以互相切换

    Predicate使用

    当开启路由网关时

    SpringCloud Gateway 将路由匹配作为 Spring WebFlux HandlerMapping基础架构的部分
    SpringCloud Gateway 包括许多内置的 RoutePredicate 工厂。所有这些Predicate都与HTTP请求的不同属性匹配,多个Route Predicate工厂可以进行组合
    Spring Cloud Gateway创建 Route对象时,使用 RoutePredicate Factory创建 Predicate对象, Predicate对象可以赋值给Route. Spring Cloud Gateway包含许多内置的 Route predicate factories
    所有这些谓词都匹配HTTP请求的不同属性。多种谓词工厂可以组合,并通过逻辑and组合

    常用的 Route Predicate
    After

    路由规则可以匹配一个时间,设置在{arg}之后,当请求的时间在配置时间之后,才会交给 route 去处理

    spring:
      cloud:
        gateway:
          routes:
          - id: after_route
            uri: https://example.org
            predicates:
            - After=2021-01-20T17:42:47.789-07:00[China/Shanghai]
    
    Before

    路由规则可以匹配一个时间,设置在{arg}之前,当请求的时间在配置时间之前,才会交给 route 去处理

    spring:
      cloud:
        gateway:
          routes:
          - id: after_route
            uri: https://example.org
            predicates:
            - Before=2021-01-20T17:42:47.789-07:00[China/Shanghai]
    
    Between

    路由规则可以匹配一个时间,设置在{arg}之间,当请求的时间在配置时间之间,才会交给 route 去处理

    spring:
      cloud:
        gateway:
          routes:
          - id: between_route
            uri: https://example.org
            predicates:
            - Between=2021-01-20T17:42:47.789-07:00[China/Shanghai], 2021-01-21T17:42:47.789-07:00[China/Shanghai]
    

    需要2个参数,一个是cookie名字,另一个是值,可以为正则表达式。它用于匹配请求中,带有该名称的cookie和cookie匹配正则表达式的请求

    spring:
      cloud:
        gateway:
          routes:
          - id: cookie_route
            uri: https://example.org
            predicates:
            - Cookie=name, zhangsan
    
    # 例
    # 请求带有cookie名为name, cookie值为 zhangsan 的请求
    # 将都会转发到uri为 https://example.org 的地址上
    
    # curl 请求
    # $ curl -H ‘Cookie:name=zhangsan’ localhost:8081
    
    • 不带cookie访问

    • 带cookie访问

    在上面的配置中,当请求的 Header 中有 X-Request-Id的header名,且header值为数字时,请求会被路由到配置的 uri

    spring:
      cloud:
        gateway:
          routes:
          - id: header_route
            uri: https://example.org
            predicates:
            - Header=X-Request-Id, d+
    
    # 例
    # $ curl -H ‘X-Request-Id:1’ localhost:8081
    

    Host

    需要一个参数即hostname,它可以使用 . 或者 * 等去匹配host。这个参数会匹配请求头中的host的值,一致,则请求正确转发

    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: https://example.org
            predicates:
            - Host=**.somehost.org,**.anotherhost.org
    
    # 如果请求的主机标头的值为 
        www.somehost.org 
        或 beta.somehost.org
        或 www.anotherhost.org
    # 则此路由匹配
    # curl 请求
    # curl -H ‘Host:www.adou.com’ localhost:8081
    

    Method

    如果请求方法是GET或POST,则此路由匹配

    spring:
      cloud:
        gateway:
          routes:
          - id: method_route
            uri: https://example.org
            predicates:
            - Method=GET,POST
    
    Path

    当请求路径满足 /red/** ,则会经过 route 到达 https://example.org

    spring:
      cloud:
        gateway:
          routes:
          - id: path_route
            uri: https://example.org
            predicates:
            - Path=/red/**
    
    Query

    也可以只填一个参数,填一个参数时,则只匹配参数名,当请求中请求参数包含 green,则会经过 route 到达 https://example.org

    spring:
      cloud:
        gateway:
          routes:
          - id: query_route
            uri: https://example.org
            predicates:
            - Query=green
            - Query=color, green
    # 配置了请求中含有参数color,并且color的值匹配green.,则请求命中路由
    # curl 请求
    # $ curl localhost:8081?color=green
    
    RemoterAddr

    请求远程地址,则会经过 route

    spring:
      cloud:
        gateway:
          routes:
          - id: remoteaddr_route
            uri: https://example.org
            predicates:
            - RemoteAddr=192.168.1.1/24
    
    # 如果请求的远程地址是 192.168.1.10 ,则此路由匹配
    
    Weight

    权重采用两个参数匹配 group 和 weight,当达成条件则会路由转发

    spring:
      cloud:
        gateway:
          routes:
          - id: weight_high
            uri: https://weighthigh.org
            predicates:
            - Weight=group1, 8
          - id: weight_low
            uri: https://weightlow.org
            predicates:
            - Weight=group1, 2
    
    # 这条路线会将大约80%的流量转发到 weighthigh.org
    # 将大约20%的流量转发到 weightlow.org
    

    说白了, Predicate就是为了实现一组匹配规则,让请求过来找到对应的 Route进行处理

    Filter使用

    路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用
    Spring Cloud Gateway内置了多种路由过滤器,他们都由 GatewayFilter 的工厂类来产生
    种类:GateWayFilterGlobalFilter

    自定义过滤器
    自定义全局GlobalFilter
    主要继承两个接口:GlobalFilter,Ordered
    作用:全局日志记录,统一网关鉴权等等

    @Component
    @Slf4j
    public class LogGateWayFilter implements GlobalFilter, Ordered {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            // 获取请求的参数
            String username = exchange.getRequest().getQueryParams().getFirst("username");
            if (username == null){
                log.info("用户名为空,找不到该用户");
                // 设置状态码
                exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
                return exchange.getResponse().setComplete();
            }
            // 返回
            log.info("进入拦截器");
            return chain.filter(exchange);
        }
    
        /**
         * 加载过滤器的顺序
         * @return
         */
        @Override
        public int getOrder() {
            return 0;
        }
    }
    

  • 相关阅读:
    【认证】Apache Shiro对象概念
    【Java基础】char
    【Http】keepalive
    【Nginx】Nginx处理请求过程
    【CSS】块级元素和行内元素
    未A,或用水法,或不熟的题
    2017初二上期中考试总结
    动态规划中的单调队列优化_补充
    NOIP2017普及组翻车记
    对拍模板
  • 原文地址:https://www.cnblogs.com/hewenhao-blogs/p/14727055.html
Copyright © 2020-2023  润新知