一、Gateway概述

1、Gateway是什么

Cloud在1.x版本中采用的都是Zuul网关,但在2.x版本中,zuul升级一直跳票,SpringCloud最后自己研发了一个网关替代Zuul,那就是 SpringCloud Gatewaty。

  • Gateway 是在 Spring 生态系统之上构建的 API 网关服务,基于 Spring 5、Spring Boot 2 和 Project Reactor 等技术。它提供了一种简单且有效的方式来对 API 进行路由,并提供了一些强大的过滤器功能(熔断、限流、重试等)。
  • Gateway 的底层是基于 WebFlux 框架实现的,而webFlux底层使用netty通信(NIO)。
  • Gateway 使用非阻塞 API,支持 WebSocket 且与 Spring 紧密集成。
  • 官网:https://spring.io/projects/spring-cloud-gateway

    2、Gateway能干什么

  • 反向代理

  • 鉴权
  • 流量控制
  • 熔断
  • 日志监控

1、Gateway 新一代网关 - 图1

3、Gateway具有的特征

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

    4、Gateway与zuul的区别

    在SpringCloud Finchley 正式版之前(现在H版),SpringCloud推荐的网关是Netflix提供的zuul。
  1. Zuul1.x 是一个基于阻塞 I/O的API网关
  2. Zuul1.x 基于Servlet2.5使用阻塞架构它不支持任何长连接 (如WebSocket)Zuul的设计模式和Nginx较像,每次I/O操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx用C++实现,Zuul用java实现,而JVM本身会有第一次加载较慢的情况,使得Zuul的性能相对较差。
  3. Zuul 2.x理念更加先进,像基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合。Zuul2.x的性能较Zuul 1.x有较大的提升。在性能方面,根据官方提供的基准测试,Spring Cloud Gateway的RPS(每秒请求次数)是Zuul的1.6倍。
  4. Spring Cloud Gateway建立在Spring Framework 5、project Reactor和Spring Boot2 之上,使用非阻塞API
  5. Spring Cloud Gateway 还支持WebSocket,并且与Spring紧密集成拥有更好的开发体验。

    二、Gateway的三大核心概念

  6. Route 路由: 路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,就是根据某些规则,将请求发送到指定服务上。

  7. Predicate 断言:参考的是Java8的java.util.function.Predicate,使开发人员能够匹配 HTTP 请求中的所有内容(请求头/请求参数),如果请求与断言相匹配则进行路由。
  8. Filter 过滤: 实现的过滤器可以在请求被路由前或者之后,对请求进行修改。

image.png

三、Gateway的工作流程

image.png

  • 客户端向 Gateway 发出请求
  • 在 Gateway Handler Mapping 中找到与请求匹配的路由,将其发送到 Gateway Handler。
  • Handler 再通过指定的过滤器链,然后将请求发送到实际的服务执行业务逻辑,最后返回。

过滤器链之间用虚线分开,是因为在发送请求之前或之后执行一些其他的业务逻辑:

  1. 之前:参数校验、权限校验、流量监控、日志输出、协议转换等。
  2. 之后:相应内容与响应头的修改、日志输出、流量监控等。

    四、Gateway入门案例

    1、Gateway搭建

  3. 创建工程 cloud-gateway-gateway9527

  4. 写pom:webflux和web模块冲突,记得删除

    1. <dependency>
    2. <groupId>org.springframework.cloud</groupId>
    3. <artifactId>spring-cloud-starter-gateway</artifactId>
    4. </dependency>
  5. 写yml ```yaml server: port: 9527

spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true # 开启从注册中心取服务名,动态创建路由的功能 routes:

  1. - id: payment_routh # 路由的 ID,没有固定规则但要求唯一
  2. uri: http://localhost:8001 # 匹配后提供服务的路由地址
  3. predicates:
  4. - Path=/payment/get/** # 断言,路径相匹配的进行路由
  5. - id: payment_routh2
  6. uri: http://localhost:8001
  7. predicates:
  8. - Path=/payment/lb/**

eureka: instance: hostname: cloud-gateway-service client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka7001.com:7001/eureka


4. 写主程序
```java
@EnableEurekaClient
@SpringBootApplication
public class GateWayApplication9527 {
    public static void main(String[] args) {
        SpringApplication.run(GateWayApplication9527.class, args);
    }
}
  1. 测试,启动7001、8001、9527,访问http://localhost:9527/payment/get/1

image.png

2、硬编码配置

GateWay的网关配置,除了支持配置文件,还支持硬编码方式,使用硬编码配置GateWay:

@Configuration
public class GateWayConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route("path_route_moke",r->r.path("/guonei")
                     .uri("http://news.baidu.com/"));
        return routes.build();
    }
}

3、动态路由 routes


从注册中心取服务名,然后匹配路径转发:
image.png
image.png

4、断言 predicates

  1. After:可以指定,只有在指定时间后,才可以路由到指定微服务,在指定的时间之前访问,都会报404。
  2. before:与after类似,他说在指定时间之前的才可以访问
  3. between:需要指定两个时间,在他们之间的时间才可以访问
  4. cookie:只有包含某些指定cookie(key,value),的请求才可以路由
  5. Header:只有包含指定请求头的请求,才可以路由
  6. Host:只有指定主机的才可以访问
  7. Method:只有指定请求才可以路由,比如get请求…
  8. Path:只有访问指定路径,才进行路由,我们已经用过了
  9. Query:必须带有请求参数才可以访问
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心取服务名,动态创建路由的功能
     routes:
      - id: payment_routh     # 路由的 ID,没有固定规则但要求唯一
       uri: http://localhost:8001 # 匹配后提供服务的路由地址
       predicates:
        - Path=/payment/get/**  # 断言,路径相匹配的进行路由
      - id: payment_routh2
       uri: http://localhost:8001
       predicates:
     predicates:
       - After=2017-01-20T17:42:47.789-07:00[Asia/Shanghai] # 时间生效
       - Before=2017-01-20T17:42:47.789-07:00[Asia/Shanghai]
       - Between=2017-01-20T17:42:47.789-07:00[Asia/Shanghai], 2017-01-21T17:42:47.789-07:00[America/Denver]
       - Cookie=chocolate, ch.p # cookie命名的请求,其值与常规表达式相匹配
       - Header=X-Request-Id, \d+ # header包含指定元素,且value是数字
       - Host=**.somehost.org,**.anotherhost.org # 指定主机才能访问
       - Method=GET,POST
       - Path=/payment/get/**,Path=/payment/lb/**

5、过滤器 Filter

  1. 路由过滤器可用于修改进入的Http请求和返回的Http响应,路由过滤器只能过滤指定路由进行使用。
  2. Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生,分为单一过滤器、全局过滤器,过滤器的类型可以在网关 (spring.io)查看。

    1、单一过滤器

    spring:
    cloud:
     gateway:
     routes:
       - id: add_request_header_route
       uri: https://example.org
     filters:
       - AddRequestHeader=X-Request-red, blue
    

    2、全局过滤器

    Spring提供了很多全局过滤器,但是我们一般使用自定义的全局过滤器足够。

  3. 自定义全局过滤器

    @Component
    @Slf4j
    public class MyLogGateWayFilter implements GlobalFilter,Ordered {
     @Override
     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
         log.info("*********come in MyLogGateWayFilter: "+new Date());
         String uname = exchange.getRequest().getQueryParams().getFirst("username");
         if(StringUtils.isEmpty(username)){
             log.info("*****用户名为Null 非法用户,(┬_┬)");
             exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//给人家一个回应
             return exchange.getResponse().setComplete();
         }
         return chain.filter(exchange);
     }
    
     @Override
     public int getOrder() {
         return 0;
     }
    }
    
  4. 加入到IOC容器

    @Bean
    public GlobalFilter customFilter() {
     return new CustomGlobalFilter();
    }