0%

【SpringCloud】服务网关:Gateway

关于Spring Cloud Gateway的使用

1 Gateway介绍

1.1 基本介绍

  • Gateway是在spring生态系统上构建的API网关服务,基于Spring5,SpringBoot2 和 Project Reactor等技术
  • Gateway提供亦庄简单而有效的方式来对API进行路由,以及提供一些强大的过滤能力,例如:熔断、限流、重试等
  • Gateway使用的Webflux种的reactor-netty响应式编程组件,底层使用了Netty

1.2 功能

  • 反向代理
  • 鉴权
  • 流量控制
  • 熔断
  • 日志监控

1.3 使用位置

1.4 选择gateway原因

  • (1)zuul1.0进入了维护阶段,而Gateway是SpringCloud团队研发的,是亲儿子产品
  • (2)Gateway是基于异步非阻塞模型上进行开发的,性能方面不需要担心
  • (3)Netflix虽然发布最新的Zuul2.x,但没有与SpringCloud整合的计划

2 三大核心概念

2.1 Route(路由)

  • 路由是构建网关的基本模块,它有ID,目标URI,一系列的断言和过滤器组成,如果断言为true,则匹配该路由

2.2 Predicate(断言)

  • 断言表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真,可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言而在部署时禁用断言
  • 开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

2.3 Filter(过滤)

  • 使用过滤器,可以在请求被路由前或者之后对请求进行修改

2.4 总结

  • web请求,通过一些匹配条件,定位到真正的服务器。并在这个转发过程的前后,进行一些精细化控制。
  • predicate就是我们的匹配条件
  • filter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由

3 Gateway工作流程

  • 路由转发+执行过滤器链

4 Gateway配置

4.1 服务搭建

  • (1)新建Modulecloud-gateway-gatway9527
  • (2)修改POM(引入依赖)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!-- eureka-client -->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- gateway -->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
  • (3)修改配置文件yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    server:
    port: 9527

    spring:
    application:
    name: cloud-gateway #服务器名称

    eureka:
    instance:
    hostname: cloud-gateway-service #eureka上主机别名
    client:
    register-with-eureka: true
    fetch-registry: true
    defaultZone: http://eurka7001.com:7001/eureka
  • (4)主启动类
    1
    2
    3
    4
    5
    6
    7
    @SpringBootApplication
    @EnableEurekaClient //注册到eureka服务中心
    public class GatewayMain9527 {
    public static void main(String[] args) {
    SpringApplication.run(GatewayMain9527.class, args);
    }
    }

4,2 网关配置

  • (1)修改yaml配置
    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: payment-route # 路由ID,名字随意(建议配合服务名)
    uri: http://localhost:8001 #断言匹配成功后,转发的路由地址
    predicates:
    - Path=/payment/get/** # 断言。路径相匹配的进行路由转发,注意Path是大写开头
  • (2)测试
    • 启动eurka服务注册中心,启动服务器,再启动网关

5 通过编码形式配置网关

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class GatewayConfig {

@Bean
public RouteLocator customerLocator(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
//参数1:路径名,参数二:函数,断言匹配路径,路由转发路径
routes.route("path_name", r -> r.path("/guonei").uri("https://news.baidu.com"));

return routes.build(); //构建
}
}

6 微服务名实现动态路由

6.1 路由访问变化

  • 添加网关前:
  • 使用网关
  • 但是上面的网关配置是将转发路由写死的,打不到负载均衡,所以需要动态路由实现负载均衡

6.2 配置动态路由

  • 修改yaml配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    spring:
    cloud:
    gateway:
    discovery:
    locator:
    enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由转发
    routes:
    - id: payment-route # 路由ID,名字随意(建议配合服务名)
    uri: lb://cloud-payment-service #lb:loadBalance负载均衡,从服务注册中心获取对应服务名的服务器
    predicates:
    - Path=/payment/lb/** # 断言。路径相匹配的进行路由转发,注意Path是大写开头
  • 测试:

    • 开启eureka7001, payment8001, payment8002,gateway9527调用接口测试

7 Predicates断言使用

7.1 断言类型

7.2 After

  • 后面跟指定时间,当当前时间在指定时间之后,此路径访问才生效
  • 使用场景:提前上架服务器,但不允许服务器被访问(游戏开服)
  • 时间格式:可以通过代码来获取时间格式
    1
    2
    3
    4
    ZonedDateTime now = ZonedDateTime.now();
    System.out.println(now);
    //2021-03-13T16:47:32.605+08:00[Asia/Shanghai]
    //日期 T 时间 xxxx[xx/xx]

7.3 Before

  • 在指定时间之前,路径访问才生效,和After相反

7.4 Between

  • 在两个指定之间之内,路径访问才生效,参数为两个时间,就比前面多一个时间参数
  • Cookie Route Predicate需要两个参数,一个是Cookie name,一个是正则表达式
  • 路由规则会通过获取对应的Cookie name值(key)和正则表达式(value)去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行
1
- Cookie=username, letere //要cookies要带上"username=letere"参数

7.6 Header

  • 请求头和Cookie样,两个参数,kv键值对
  • 带有此kv键值对就匹配成功,进行路由转发

8 Filter过滤器使用

8.1 Filter介绍

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

8.2 Filter分类

  • 生命周期
    • pre
    • post

8.3 自定义过滤器

  • (1)实现GlobalFilter和Ordered接口
  • (2)重写里面的方法
  • 例子:配置一个过滤器,请求参数必须要带”uname”才放行
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    @Component
    @Slf4j
    public class LogGatewayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    log.info("******** come from LogGatewayFilter:" + new Date());
    String uname = exchange.getRequest() //获取请求
    .getQueryParams() //获取查询参数
    .getFirst("uname"); //获取对应参数值

    if(uname == null) {
    log.info("********用户名为null,非法用户,o(╥﹏╥)o");
    exchange.getResponse() //获取响应
    .setStatusCode(HttpStatus.NOT_ACCEPTABLE); //响应会状态码
    return exchange.getResponse().setComplete(); //拦截返回信息
    }
    return chain.filter(exchange); //放行
    }

    @Override
    public int getOrder() { //过滤器执行顺序,越小优先级越高
    return 0;
    }
    }