SpringCloud搭建微服务之Gateway网关

1. 概述

Gateway是在Spring生态系统之上构建的API网关服务,旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,基于WebFlux框架实现,而WebFlux框架底层又使用了高性能的Reactor模式通信框架Netty。常用功能有反向代理、鉴权、流量控制、熔断和日志监控

1.1. Gateway特性

  1. 动态路由:能够匹配任何请求属性
  2. 可以对路由指定Predicate(断言)和Filter(过滤器),且易于编写
  3. 集成Hystrix断路器功能
  4. 集成Spring Cloud服务发现功能
  5. 请求限流功能
  6. 支持路径重写

1.2. 核心概念

Route(路由)
是构建网关的基本模块,由ID、目标URI、一系列断言和过滤器组成,断言为true时匹配该路由
Predicate(断言)
请求与断言相匹配则进行路由
Filter(过滤)
可以在请求被路由前或之后对请求进行修改

1.3. Gateway网关请求流程

  1. 客户端向Gateway发出请求,然后在Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway Web Handler
  2. Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回
  3. 过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(pre)或之后(post)执行业务逻辑
  4. Filter在pre类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换
  5. 在post类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等

流程图如下
SpringCloud搭建微服务之Gateway网关_第1张图片

2. 搭建Gateway网关服务

2.1. 引入核心依赖

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-gatewayartifactId>
dependency>

2.2. 编写application.yml配置文件

server:
  port: 8812
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: provider_routh
          uri: http://localhost:8770
          predicates:
            - Path=/provider/getProviderInfo/**

2.3. 编写主启动类

@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

2.4. 验证

依次启动Eureka Server、Provider和Gateway三个微服务,在浏览器输入地址http://localhost:8812/provider/getProviderInfo/world
SpringCloud搭建微服务之Gateway网关_第2张图片

2.5. 代码配置网关

新建一个GatewayConfig类

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("provider_routh", predicate -> predicate.path("/provider/getProviderConfigInfo/**")
                .uri("http://localhost:8770")).build();
        return routes.build();
    }
}

再次启动Gateway服务,在浏览器地址输入http://localhost:8812/provider/getProviderConfigInfo/zhangsan就可以直接跳转到百度新闻网
SpringCloud搭建微服务之Gateway网关_第3张图片

3. 通过微服务名称实现动态路由

默认情况下Gateway会根据注册中心注册的服务列表, 以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

3.1. 引入Eureka Client依赖

<dependency>
   <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>

3.2. 修改application.yml

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Path=/provider/getProviderInfo/**

3.3. 验证

在浏览器地址栏输入http://localhost:8812/provider/getProviderInfo/zhangsan
SpringCloud搭建微服务之Gateway网关_第4张图片

4. Route Predicate

Spring Cloud Gateway包括许多内置的Route Predicate工厂,所有这些Predicate都与HTTP请求的不同属性匹配,多个Route Predicate工厂可以进行组合,常见的如下:

4.1. After Route Predicate

指定日期(ZonedDateTime)之后才能访问请求路径

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - After=2022-09-07T17:42:47.789+08:00[Asia/Shanghai]

4.2. Before Route Predicate

指定日期(ZonedDateTime)之前才能访问请求路径

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Before=2022-09-08T17:42:47.789+08:00[Asia/Shanghai]

4.3. Between Route Predicate

指定日期(ZonedDateTime)之间才能访问请求路径

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Between=2022-09-07T17:42:47.789+08:00[Asia/Shanghai], 2022-09-08T17:42:47.789+08:00[Asia/Shanghai]

4.4. Cookie Route Predicate

通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Cookie=username, zhangsan

4.5. Header Route Predicate

请求中必须带有消息头,且要匹配名称和值

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Header=X-Request-Id, \d+

4.6. Host Route Predicate

一组匹配的域名列表,用.号作为分隔符,通过参数中的主机地址作为匹配规则

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Host=**.xlhj.org,**.xlhj.com

4.7. Method Route Predicate

HTTP请求方式进行匹配POST/GET

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Method=GET,POST

4.8. Path Route Predicate

请求路径进行匹配

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Path=/provider/getProviderInfo/**

4.9. Query Route Predicate

查询条件匹配,一个参数时,表示请求参数中必须包含此值;两个参数时,表示请求参数中包含此值,参数值匹配第二个参数

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Query=username, zhangsan

4.10. RemoteAddr Route Predicate

IP地址进行匹配

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - RemoteAddr=192.168.1.1/24

4.11. Weight Route Predicate

权重进行匹配

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Weight=group1, 2
        - id: order_routh
          uri: http://localhost:8770
          predicates:
            - Weight=group1, 8

20%请求走上面服务,80%请求走下面服务

5. 过滤器Filter

用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用,主要有两类,即GatewayFilter和GlobalFilter

5.1. 常用过滤器

AddRequestHeader:请求头过滤器

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Path=/provider/getProviderInfo/**
          filters:
            - AddRequestHeader=X-Request-Id, xlhj

AddRequestParameter:请求参数过滤器

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER #匹配后提供服务的路由地址
          predicates:
            - Path=/provider/getProviderInfo/**
          filters:
            - AddRequestParameter=X-Request-Id, xlhj

其他过滤器用法都差不多

5.2. 自定义过滤器

自定义全局过滤器需要实现GlobalFilter和Ordered两个接口,常用语全局日志记录和统一权限认证,新建一个GatewayGlobalFilter类,代码如下:

@Component
public class GatewayGlobalFilter implements GlobalFilter, Ordered {

    private static final Logger logger = LoggerFactory.getLogger(GatewayGlobalFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        logger.info("执行自定义全局过滤器");
        String requestId = exchange.getRequest().getQueryParams().getFirst("X-Request-Id");
        if (StringUtils.isBlank(requestId)) {
            logger.info("请求参数为空!");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

5.3. 验证

重新启动gateway微服务,浏览器地址栏输入http://localhost:8812/provider/getProviderInfo/world?X-Request-Id=xlhj
SpringCloud搭建微服务之Gateway网关_第5张图片

你可能感兴趣的:(SpringCloud,微服务,spring,cloud,gateway,网关)