14.服务网关Zuul和Gateway

zuul分为两个版本,zuul1已经提更,zuul2还没开发好!
重点学习gateway!

cloud全家桶中有个很重要的组件就是网管,在1.x版本中采用的时Zuul网关
但在2.x版本中,zuul的升级一致跳票,SpringCloud最后自己研发了一个网关代替Zuul
这就是Spring Cloud Gateway,一句话:gateway时原zuul1.x版的替代!

gateway是基于异步非阻塞模型上进行开发的,性能方面不需要担心!
zuul1是基于Servlet2.5使用阻塞架构上开发的,它不支持任何长连接(如WebSocket)
GateWay的三大核心概念:
    1.Route(路由):路由是构建网关的基本模块,它是由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
    2.Predicate(断言):开发人员可以匹配HTTP请求中的所有内容(例如请求头或者请求参数),如果请求和断言相匹配则进行路由
    3.Filter(过滤):指的是spring框架中GatewayFiletr实例,使用过滤器,可以在请求被路由前或者后对请求进行修改!
 
Gateway的核心逻辑就是:路由转发和执行过滤器链 

代码构建:
    gateway是一个单独的项目,去给其他cloud项目访问加上一层网关
1.pom文件中的内容:
    <dependencies>
        重点:gateway的jar包
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--一般基础通用配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cn.com.springcloud</groupId>
            <artifactId>common</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
    
2.springboot启动类:
    @SpringBootApplication
    @EnableEurekaClient
    public class SpringBootGateway9527 {
        public static void main(String[] args) {
            SpringApplication.run(SpringBootGateway9527.class,args);
        }
    }
3.springboot的配置文件写法:
server:
  port: 9527
eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      #单机版
      #defaultZone: http://localhost:7001/eureka
      # 集群版
      defaultZone: http://eureka7001:7001/eureka,http://eureka7002:7002/eureka
  instance:
    instance-id: cloud-gateway-service9527
    prefer-ip-address: true

spring:
  application:
    name: cloud-gateway-service
  #重点
  cloud:
    gateway:
      routes:
        - id: producer_queryUserById #路由的id,没有固定规则但要求唯一,建议符合服务名称
          uri: http://localhost:8001 #匹配后提供服务的路由地址
          predicates:
            - Path=/producer/queryUserById/** #断言,服务端路径匹配的进行路由

        - id: producer_getCurrentThread
          uri: http://localhost:8001
          predicates:
            - Path=/producer/getCurrentThread/**
            
上述配置的意思是:
    当访问的是gateway:http://localhost:9527/producer/queryUserById/7时,
    满足上述的断言,此时会路由到http://localhost:8001//producer/queryUserById/7(路径拼接)

如果嫌需要给服务项目的每个请求方法都加上网关,可以这么写:
spring:
  application:
    name: cloud-gateway-service
  cloud:
    gateway:
      routes:
        - id: producer_queryUserById #路由的id,没有固定规则但要求唯一,建议符合服务名称
          uri: http://localhost:8001 #匹配后提供服务的路由地址
          predicates:
            重点:服务项目的每个请求前都设置一个公共的路径/producer,然后根据此进行配置,这样就不需要单独每个方法都配置了!
            - Path=/producer/** #断言,服务端路径匹配的进行路由
发现上述有问题:
  1.服务提供端一般都是以集群形式部署,在配置文件中写死ip和端口不好
  2.如何在网管处实现负载均衡呢?
在application.yam中配置如下:
server:
  port: 9527
eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      #单机版
      #defaultZone: http://localhost:7001/eureka
      # 集群版
      defaultZone: http://eureka7001:7001/eureka,http://eureka7002:7002/eureka
  instance:
    instance-id: cloud-gateway-service9527
    prefer-ip-address: true

spring:
  application:
    name: cloud-gateway-service
  cloud:
    gateway:
      discovery:
        locator:
          #重点:加上该配置
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由
      routes:
        - id: producer_queryUserById #路由的id,没有固定规则但要求唯一,建议符合服务名称
          #重点2:这里本身写服务提供端的地址,此时可以写服务注册在eureka注册中心的名称,lb:loadbalance(轮训的负载均衡)
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Path=/getPerson/** #断言,服务端路径匹配的进行路由

        - id: producer_getCurrentThread
          uri: lb://CLOUD-PROVIDER
          predicates:
            - Path=/producer/timesleep/**
            
测试:
    此时若通过http://localhost:9527/getPerson/10007去访问时,发现是轮训的去访问服务集群!

predicates讲解

参考地址:https://blog.csdn.net/u012367513/article/details/86356708
    predicates(断言):可以加很多种规则,目的就是让请求过来找到合适的Route进行处理
    

1. After Route Predicate Factory:使用的是时间作为匹配规则,只要当前时间大于设定时间,路由才会匹配请求。
    spring:
      cloud:
        gateway:
          routes:
          - id: after_route
            uri: http://www.google.com
            predicates:
            - After=2018-12-25T14:33:47.789+08:00
这个路由规则会在东8区的2018-12-25 14:33:47后,将请求都转跳到google。

2.Before Route Predicate Factory:使用时间作为匹配规则,只要当前时间小于设定时间,路由才会匹配请求。
    spring:
      cloud:
        gateway:
          routes:
          - id: before_route
            uri: http://www.google.com
            predicates:
            - Before=2018-12-25T14:33:47.789+08:00
这个路由规则会在东8区的2018-12-25 14:33:47前,将请求都转跳到google。

3.Between Route Predicate Factory:使用两个时间作为匹配规则,只要当前时间大于第一个设定时间,并小于第二个设定时间,路由才会匹配请求。
    spring:
      cloud:
        gateway:
          routes:
          - id: between_route
            uri: http://www.google.com
            predicates:
            - Between=2018-12-25T14:33:47.789+08:00, 2018-12-26T14:33:47.789+08:00
这个路由规则会在东8区的2018-12-25 14:33:47到2018-12-26 14:33:47之间,将请求都转跳到google。

4. Cookie Route Predicate Factory:使用的是cookie名字和正则表达式的value作为两个输入参数,请求的cookie需要匹配cookie名和符合其中value的正则。
    spring:
      cloud:
        gateway:
          routes:
          - id: cookie_route
            uri: http://www.google.com
            predicates:
            - Cookie=cookiename, cookievalue
路由匹配请求存在cookie名为cookiename,cookie内容匹配cookievalue的,将请求转发到google。

5.Header Route Predicate Factory:与Cookie Route Predicate Factory类似,也是两个参数,一个header的name,一个是正则匹配的value。
    spring:
      cloud:
        gateway:
          routes:
          - id: header_route
            uri: http://www.google.com
            predicates:
            - Header=X-Request-Id, \d+
路由匹配存在名为X-Request-Id,内容为数字的header的请求,将请求转发到google。

6. Host Route Predicate Factory:使用的是host的列表作为参数,host使用Ant style匹配。
    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: http://www.google.com
            predicates:
            - Host=**.somehost.org,**.anotherhost.org
路由会匹配Host诸如:www.somehost.org 或 beta.somehost.org或www.anotherhost.org等请求。

7. Method Route Predicate Factory:是通过HTTP的method来匹配路由。
    spring:
      cloud:
        gateway:
          routes:
          - id: method_route
            uri: http://www.google.com
            predicates:
            - Method=GET
路由会匹配到所有GET方法的请求。

8.Path Route Predicate Factory:使用的是path列表作为参数,使用Spring的PathMatcher匹配path,可以设置可选变量。
    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: http://www.google.com
            predicates:
            - Path=/foo/{segment},/bar/{segment}
上面路由可以匹配诸如:/foo/1 或 /foo/bar 或 /bar/baz等
其中的segment变量可以通过下面方式获取:
PathMatchInfo variables = exchange.getAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE);
Map<String, String> uriVariables = variables.getUriVariables();
String segment = uriVariables.get("segment");
在后续的GatewayFilter Factories就可以做对应的操作了。

9.Query Route Predicate Factory:可以通过一个或两个参数来匹配路由,一个是查询的name,一个是查询的正则value。
    spring:
      cloud:
        gateway:
          routes:
          - id: query_route
            uri: http://www.google.com
            predicates:
            - Query=baz
路由会匹配所有包含baz查询参数的请求。
    spring:
      cloud:
        gateway:
          routes:
          - id: query_route
            uri: http://www.google.com
            predicates:
            - Query=foo, ba.
路由会匹配所有包含baz,并且baz的内容为诸如:bar或baz等符合ba.正则规则的请求。

10.RemoteAddr Route Predicate Factory:通过无类别域间路由(IPv4 or IPv6)列表匹配路由。
    spring:
      cloud:
        gateway:
          routes:
          - id: remoteaddr_route
            uri: http://www.google.com
            predicates:
            - RemoteAddr=192.168.1.1/24
上面路由就会匹配RemoteAddr诸如192.168.1.10等请求。

11.Modifying the way remote addresses are resolved

Filter:过滤器

分类:
    1.GatewayFilter
    2.GlobalFilter
    3.上述两种的配置种太多,不如自己去实现代码来的方便

自定义的过滤器:
    1.两个主要的接口:
    2.能干嘛;
         2.1全局日志记录
        2.2统一通关鉴权
        
样例:创建自己的过滤器,加上@Component注解将其加载到容器中
    @Component
    @Slf4j
    重点1:实现两个接口:GlobalFilter和Ordered(用来控制该过滤器的执行顺序,数值越小,越先执行!)
    public class MyLogGateWayFilter implements GlobalFilter, Ordered {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            重点2:hutool工具包的使用
            log.info("*****gateWay的自定义过滤器:时间:"+ DateUtil.formatDateTime(new Date()));
            重点3:获取请求中的uname属性值
            String uanme=exchange.getRequest().getQueryParams().getFirst("uname");
            if(uanme == null){
                log.info("********用户名为null,非法用户,/(ㄒoㄒ)/~~");
                重点4:设置返回的状态码:406
                exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                重点5:表示消息处理完毕,可以进行结束
                return exchange.getResponse().setComplete();
            }
            重点6:该该条过滤的ServerWebExchange 对象传入到过滤链中的下一个过滤环节!
            return chain.filter(exchange);
        }
        重点7:过滤的执行顺序,数字越小,越先执行!
        @Override
        public int getOrder() {
            return 0;
        }
    }

 

posted @ 2022-05-29 17:40  努力的达子  阅读(1135)  评论(0编辑  收藏  举报