• 微服务网关之SpringCloudGateway


    一、SpringCloudGateway

    1.1 简介

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

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

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

    官网文档

    1.2 名词解释

    • Filter(过滤器):

      和 Zuul 的过滤器类似,可以使用它拦截和修改请求,并且对上游的响应,进行二次处理。过滤器为 org.springframework.cloud.gateway.filter.GatewayFilter 类的实例。
      
    • Route(路由):

      网关配置的基本组成模块,和 Zuul 的路由配置模块类似。一个 Route 模块 由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配,目标URI会被访问。
      
    • Predicate(断言):

      这是一个 Java 8 的 Predicate,可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。断言的 输入类型是一个 ServerWebExchange。
      

    1.3 Gateway 处理流程

    客户端向 Spring Cloud Gateway 发出请求,在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web HandlerHandler 通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。

    二、准备工作

    2.1 创建 OrderService 模块

    1. 添加依赖
    <properties>
        <java.version>1.8</java.version>
        <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
    </dependencies>	
    
    1. 编写配置文件
    spring:
      application:
        # 服务名称
        name: order-service
    
      cloud:
        nacos:
          discovery:
            # 注册服务中心地址
            server-addr: 192.168.205.10:8848
    server:
      # 设置服务端口
      port: 8881            
    
    1. 创建 OrderController
    @RestController
    @RequestMapping("/order")
    public class OrderController {
    
        @RequestMapping("/create")
        public String create() {
            return "订单创建成功";
        }
    
    }
    

    4) 启动应用,访问 http://localhost:8881/order/create ,返回:

    订单创建成功
    

    2.2 创建网关模块

    1. 添加依赖
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    

    三、路由配置方式

    3.1 基于配置文件指定URI路由配置方式

    spring:
      application:
        # 配置应用名称
        name: gateway
      cloud:
        gateway:
          routes:
            - id: order-service
              uri: http://localhost:8881
              predicates:
                - Path=/order/**
    server:
      # 配置应用端口
      port: 8080
    

    配置说明:

    * routes : 表示路由配置,可以存在多个
    * id:自定义的路由 ID,保持唯一
    * uri:目标服务地址
    * predicates::路由条件,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。
    *- Path:基于路径路由     
    

    上面的配置用文字表达如下:

    配置一个 Id 为 order-service 的路由规则,当访问地址以 /order 开头时,将会把请求转发到 http://localhost:8881 上去
    

    3.2 基于代码的路由配置方式

    @SpringBootApplication
    public class GatewayApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(GatewayApplication.class, args);
        }
    
        @Bean
        public RouteLocator orderRouteLocator(RouteLocatorBuilder builder) {
            return builder.routes()
                    .route("path_route", r -> r.path("/order/**")
                            .uri("http://localhost:8881"))
                    .build();
        }
    }
    
    

    3.3 与注册中心相结合的路由配置方式

    1. 添加依赖
    <dependencyManagement>
        <dependencies>
            ......
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
        <dependencies>    
    <dependencyManagement>   
    
    <dependencies>    
    	<dependency>
    		<groupId>com.alibaba.cloud</groupId>
    		<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    	</dependency>    
    </dependencies>    
    
    1. 调整配置
    spring:
      application:
        # 配置应用名称
        name: gateway
      cloud:
        nacos:
          discovery:
            # 注册服务中心地址
            server-addr: 192.168.205.10:8848
        gateway:
          routes:
            - id: order-service
              # 与单个URL的区别仅仅在于URI的schema协议不同
              uri: lb://order-service
              predicates:
                - Path=/order/**
    server:
      # 配置应用端口
      port: 8080
    

    四、匹配规则

    Spring Cloud Gateway 是通过 Spring WebFluxHandlerMapping 做为底层支持来匹配到转发路由,它内置了很多 Predicates 工厂,这些 Predicates 工厂通过不同的 HTTP 请求参数来匹配,多个 Predicates 工厂可以组合使用。

    4.1 Predicate 断言条件介绍

    Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。可以用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。

    Spring Cloud GatewaySpring 利用 Predicate 的特性实现了各种路由匹配规则,有通过 Header、请求参数等不同的条件来进行作为条件匹配到对应的路由。下图总结了 Spring Cloud 内置的几种 Predicate 的实现:

    4.2 匹配方式

    方式名称 参数名 实例
    通过请求参数匹配 Query - Query=name,aaa
    通过 Header 属性匹配 Header - Header=X-Request-Id, d+
    通过Cookie匹配 Cookie - Cookie=sessionId,1001
    通过 Host 匹配 Host - Host=..com
    通过请求方式匹配 Method - Method=GET
    通过请求路径匹配 Path - Path=/order/**
    通过请求 ip 地址进行匹配 RemoteAddr - RemoteAddr=192.168.1.1/24

    4.3 通过请求参数匹配实例

    Query Route Predicate 支持传入两个参数,一个是属性名一个为属性值,属性值可以是正则表达式。

    spring:
      application:
        # 配置应用名称
        name: gateway
      cloud:
        nacos:
          discovery:
            # 注册服务中心地址
            server-addr: 192.168.205.10:8848
        gateway:
          routes:
            - id: order-service
              uri: lb://order-service
              predicates:
                - Query=name
    

    只有包含属性名 name 才会转发,如 http://localhost:8080/order/create?name=aaa

    Query 值可以以键值对的方式进行配置:

    spring:
      application:
        # 配置应用名称
        name: gateway
      cloud:
        nacos:
          discovery:
            # 注册服务中心地址
            server-addr: 192.168.205.10:8848
        gateway:
          routes:
            - id: order-service
              uri: lb://order-service
              predicates:
                - Query=name,aaa
    

    只有当请求中包含属性名 name 并且值为 aaa 才会转发 ,http://localhost:8080/order/create?name=aaa

    4.3 通过 Header 属性匹配实例

    spring:
      application:
        # 配置应用名称
        name: gateway
      cloud:
        nacos:
          discovery:
            # 注册服务中心地址
            server-addr: 192.168.205.10:8848
        gateway:
          routes:
            - id: order-service
              uri: lb://order-service
              predicates:
    			# d 表示匹配数字,+ 表示1 次或多次匹配。
                - Header=X-Request-Id, d+
    

    通过 postman 发起请求,在 header 头上增加属性 X-Request-Id ,配置值为任意数值,如 99,即可访问成功。

    五、Filter

    路由过滤器允许以某种方式修改传入的 HTTP 请求传出的 HTTP 响应,路由过滤器适用于特定路由。

    5.1 生命周期

    SpringCloudGateway 的 Filter 的生命周期不像 Zuul 的那么丰富,它只有两个:prepost

    • PRE: 过滤器在请求被路由之前调用。可用来实现身份验证、在集群中选择请求的微服务、记录调试信息等。
    • POST:过滤器在路由到微服务以后执行。可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。

    5.3 分类

    Spring Cloud GatewayFilter 从作用范围可分为两种 GatewayFilterGlobalFilter

    • GatewayFilter:应用到单个路由或者一个分组的路由上。
    • GlobalFilter:应用到所有的路由上。

    5. 2 GatewayFilter 内置工厂

    Spring Cloud Gateway 包括许多内置的 GatewayFilter工厂

    工厂名称 作用
    AddRequestHeaderGatewayFilterFactory 添加请求头的过滤器工厂
    AddRequestParameterGatewayFilterFactory 添加请求参数的过滤器工厂
    AddResponseHeaderGatewayFilterFactory 添加响应头的过滤器工厂
    DedupeResponseHeaderGatewayFilterFactory 删除重复响应头的过滤器工厂
    HystrixGatewayFilterFactory Hystrix 过滤器工厂
    PrefixPathGatewayFilterFactory 添加前缀路径的过滤器工厂
    PreserveHostHeaderGatewayFilterFactory 保留原请求头的过滤器工厂
    RequestRateLimiterGatewayFilterFactory 保留限流头的过滤器工厂
    RedirectToGatewayFilterFactory 重定向的过滤器工厂
    RemoveRequestHeaderGatewayFilterFactory 删除请求头的过滤器工厂
    RemoveResponseHeaderGatewayFilterFactory 删除响应头的过滤器工厂
    RemoveRequestParameterGatewayFilterFactory 删除请求参数的过滤器工厂
    RewritePathGatewayFilterFactory 重写路径的过滤器工厂
    RewriteLocationResponseHeaderGatewayFilterFactory 重写本地响应头的过滤器工厂
    RewriteResponseHeaderGatewayFilterFactory 重写响应头的过滤器工厂
    SaveSessionGatewayFilterFactory 保存 session 的过滤器工厂
    SecureHeadersGatewayFilterFactory 安全头的过滤器工厂
    SetPathGatewayFilterFactory 设置路径的过滤器工厂
    SetRequestHeaderGatewayFilterFactory 设置请求的过滤器工厂
    SetResponseHeaderGatewayFilterFactory 设置响应的过滤器工厂
    SetStatusGatewayFilterFactory 设置状态的过滤器工厂
    StripPrefixGatewayFilterFactory StripPrefix过滤器工厂
    RetryGatewayFilterFactory 重试过滤器工厂
    RequestSizeGatewayFilterFactory 请求大小限制过滤器工厂
    SetRequestHostGatewayFilterFactory 设置主机的过滤器工厂

    5.3 实例之AddRequestHeaderGatewayFilterFactory

    spring:
      cloud:
        gateway:
          routes:
            - id: order-service
              uri: lb://order-service
              filters:
                - AddRequestHeader=age,18
    

    过滤器工厂会在匹配的请求头加上一对请求头,名称为 age,值为18

    5.4 自定义过滤器

    除了使用默认的内置过滤器,我们还可以自己实现过滤器。

    1. 创建自定义过滤器
    public class MyGatewayFilter implements GatewayFilter, Ordered {
    
        private static final Logger log = LoggerFactory.getLogger(MyGatewayFilter.class);
    
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info("this is a pre filter");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("this is a post filter");
            }));
        }
    
    
        /**
         * 设定优先级别的,值越大则优先级越低
         *
         * @return
         */
        public int getOrder() {
            return 0;
        }
    }
    
    1. 路由配置过滤器
    @Bean
    public RouteLocator orderRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("path_route", r -> r.path("/order/**")
                        .filters(f -> f.filter(new MyGatewayFilter()))
                        .uri("http://localhost:8881")
                        .order(0)
                )
                .build();
    }
    
    1. 启动项目,访问 http://localhost:8080/order/create,查看控制台输出:
    2020-09-07 15:23:17.612  INFO 15348 --- [ctor-http-nio-2] c.l.c.gateway.filter.MyGatewayFilter     : this is a pre filter
    2020-09-07 15:23:18.427  INFO 15348 --- [ctor-http-nio-4] c.l.c.gateway.filter.MyGatewayFilter     : this is a post filter
    

    5.5 自定义过滤器工厂

    通过自定义过滤器工厂,可以实现在配置文件中配置过滤器。

    过滤器工厂的顶级接口是 GatewayFilterFactory ,有2个两个较接近具体实现的抽象类,分别为AbstractGatewayFilterFactoryAbstractNameValueGatewayFilterFactory,前者接收一个参数,比如它的实现类 RedirectToGatewayFilterFactory ;后者接收2个参数,比如它的实现类AddRequestHeaderGatewayFilterFactory 类。

  • 相关阅读:
    HR人员基本信息、分配信息和地址信息SQL
    iframe下面的session问题
    主流NOSQL数据库之MongoDB快速入门
    CookieThemeResolver
    data binding&&conversionservice
    二进制权限管理(转)
    Spring MVC 对locale和theme的支持
    OpenSessionInViewFilter类作用
    Spring数据库访问之ORM(三)
    Spring自定义属性编辑器PropertyEditorSupport + 使用CustomEditorConfigurer注册属性编辑器
  • 原文地址:https://www.cnblogs.com/markLogZhu/p/13607834.html
Copyright © 2020-2023  润新知