2.3 Gateway网关服务

一、网关作用介绍

  1. 网关功能:

    1. 身份认证和权限校验

    2. 服务路由、负载均衡

    3. 请求限流

  2. SpringCloud中实现网关的两个组件

    1. gateway:基于Spring5中提供的WebFlux,属于响应式编程,具备更好的性能

    2. zuul(已停止维护):Zuul是基于Servlet的实现,属于阻塞式编程

二、快速入门

  1. 搭建网关服务

    1. 坐标依赖:

              <!--  Gateway组件依赖  -->
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-gateway</artifactId>
              </dependency>
      
              <!--  Nacos发现依赖  -->
              <dependency>
                  <groupId>com.alibaba.cloud</groupId>
                  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
              </dependency>
      
              <!--  需要引入负载均衡依赖  -->
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-loadbalancer</artifactId>
              </dependency>

      备注:SpringBoot2.4以及以上版本需要手动导入负载均衡依赖,否则报错!!!!

    2. 编写配置文件以及nacos地址

      server:
        port: 10010
      
      spring:
        application:
          name: gateway
        cloud:
          nacos:
            server-addr: 49.233.26.144:60000 # nacos地址
          gateway: # 网关配置
            routes:  # 网关路由配置
              - id: user-service # 路由标识,自定义,只要唯一即可
      #          uri: http://127.0.0.1:8081 # 路由的目标地址 http就是一个固定地址,不建议使用
                uri: lb://user-service # 路由目标地址 lb是负载均衡,后面跟随服务名称 强烈推荐
                predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
                  - Path=/user/** # 这格式按照路径匹配,只要是以/user/开头的就符合要求,路径断言

三、路由断言工厂

  1. 网关路由可以配置的内容包括:

    1. 路由id:路由唯一标识

    2. uri:路由目的地,支持lb和http两种

    3. predicates:路由断言,判断请求是否符合要求,符合要求才会转发到路由目的

    4. filters:路由过滤器,处理请求或响应

  2. 路由断言工厂(Route Predicate Factory)

    1. 我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件

      1. 例如Path=/user/**是按照路径匹配的,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的

      2. 像这样的断言工厂不还有10多个

    2. Spring提供了11种基本的断言工厂

      名称
      说明
      示例

      After

      是某个时间点后的请求

      - After=2037-01-20T17:42:47.789-07:00[America/Denver]

      Before

      是某个时间点之前的请求

      - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]

      Between

      是某两个时间点之间的请求

      - Between=2037-01-20T17:42:47.789-07:00[America/Denver],2037-03-20T17:42:47.789-07:00[America/Denver]

      Cookie

      请求必须包含某些cookie

      - Cookie=chocolate,ch.p

      Header

      请求种必须包含某些Header

      - Header=X-Request-Id,\d+

      Host

      请求必须是访问某个Host(域名)

      - Host=**.lonelysnow.cn

      Method

      请求方式必须是指定方式

      - Method=GET, POST

      Path

      请求路径必须符合指定规则

      - Path=/red/{segment},/blue/**

      Query

      请求参数必须包含指定参数

      - Query=name,Jack

      RemoteAddr

      请求者的ip必须是指定范围

      - RemoteAddr=192.168.1.1/24

      Weight

      权重处理

      备注:如果有使用的,可以直接官方查看文档,表格中的示例也是使用方式

四、路由过滤器配置——GatewayFilter

  1. GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的相应做处理

  2. Spring提供了31中过滤工厂,例如:

    名称
    说明

    AddRequestHeader

    给当前请求添加一个请求头

    RemoveRequestHeader

    移除请求中的一个请求头

    AddResponseHeader

    给响应结果中添加一个响应头

    RemoveResponseHeader

    移除响应结果中的一个响应头

    RequestRateLimiter

    限制请求的流量

    ……

    ……

    备注:其他详细的可以到官网上查看

  3. 给服务添加过滤器配置:

    spring:
      cloud:
        gateway:
          routes:  # 网关路由配置
            - id: user-service # 路由id,自定义,只要唯一即可
    #          uri: http://127.0.0.1:8081 # 路由的目标地址 http就是一个固定地址,不建议使用
              uri: lb://user-server # 路由目标地址 lb是负载均衡,后面跟随服务名称 强烈推荐
              predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
                - Path=/user/** # 这格式按照路径匹配,只要是以/user/开头的就符合要求
              filters: # 只给userService加请求头
                - AddRequestHeader=Truth,addHeader OK # 添加一个请求头内容
            - id: order
              uri: lb://order-service
              predicates:
                - Path=/order/**
  4. 配置全局默认过滤器(所有请求均生效)

    spring:
        gateway:
          routes:  # 网关路由配置
            - id: user-service # 路由id,自定义,只要唯一即可
    #          uri: http://127.0.0.1:8081 # 路由的目标地址 http就是一个固定地址,不建议使用
              uri: lb://user-server # 路由目标地址 lb是负载均衡,后面跟随服务名称 强烈推荐
              predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
                - Path=/user/** # 这格式按照路径匹配,只要是以/user/开头的就符合要求
    #          filters: # 只给userService加请求头
    #            - AddRequestHeader=Truth,addHeader OK # 添加一个请求头内容
            - id: order
              uri: lb://order-service
              predicates:
                - Path=/order/**
          default-filters: # 配置全局默认过滤器
            - AddRequestHeader=Truth,addHeader OK

五、全局过滤器——GlobalFilter

  1. 全局过滤器的作用也是处理一切进入网管的请求和微服务响应,与GatewayFilter的作用一样,类似default-filters

  2. 区别在于GatewayFilter通过配置定义,处理逻辑是固定的,而GlobalFilter的逻辑需要自己写代码实现

  3. 定义方法:实现GlobalFilter接口

    // 接口介绍
    public interface GlobalFilter {
        /**
         * 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
         *
         * @param exchange  请求上下文,这里可以获取Request、Response等信息
         * @param chain 用来把请求委托给下一个过滤器
         * @return {@code Mono<void>} 返回标识当前过滤器业务结束
         */
        Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
    }
  4. 案例:定义全局过滤器,拦截请求,判断请求的参数是否满足以下条件

    1. 参数中是否有authorization,

    2. authorization参数值是否为admin

    3. 同时满足上面两个条件,放行,否则拦截

    // 交给Spring管理
    @Component
    // 过滤器执行顺序
    //@Order(-1)
    public class AuthorFilter implements GlobalFilter, Ordered {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            // 获取请求参数
            ServerHttpRequest request = exchange.getRequest();
            MultiValueMap<String, String> params = request.getQueryParams();
    
            // 获取参数中的authorization
            String auth = params.getFirst("authorization");
    
            // 判断值是否为admin;是,放行;否,拦截
            if ("admin".equals(auth)) {
                // 放行
                return chain.filter(exchange);
            }
            // 设置状态码,不然直接结束没有相应
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            // 拦截,直接结束
            return exchange.getResponse().setComplete();
        }
    
        @Override
        public int getOrder() {
            return -1;
        }
    }

    备注:过滤器一定要定义顺序,可以使用注解直接定义,也可以实现接口

六、过滤器执行顺序

  1. 请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter

  2. 请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链中(集合中),排序后依次执行每个过滤器

  3. 每一个过滤器都必须指定一个int类型的order值,,order值越小,优先级越高,执行顺序越靠前

  4. GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定

  5. 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序,从1递增

  6. 当过滤器的order值相同时,会按照 deaultFilter > 路由过滤器 > GlobalFilter的顺序执行

七、CORS跨域配置

  1. 跨域:域名不一致就是跨域,主要包括:

    1. 域名不同:包括二级域名不同

    2. 域名相同,端口不同

  2. 跨域问题:浏览器禁止请求的发起者与服务器端发生跨域Ajax请求,请求被浏览器拦截的问题

  3. 解决方案:CORS

  4. Gateway配置跨域请求

    spring:
      cloud:
        gateway:
          globalcors:
            add-to-simple-url-handler-mapping: true # 解决options请求被拦截的问题
            cors-configurations: 
              '[/**]':
                allowedOrigins: # 允许那些网站的跨域请求
                  - "http://localhost:8090"
                  - "http://域名"
                allowedMethods: # 允许的跨域Ajax请求方式
                  - "GET"
                  - "POST"
                  - "DELETE"
                  - "PUT"
                  - "OPTIONS"
                allowedHeaders: "*" # 允许在请求中携带头信息
                allowCredentials: true # 是否允许携带Cookie
                maxAge: 36000 # 这次跨域检测的有效期

最后更新于

这有帮助吗?