SpringCloud GateWay 使用说明

前言:

gateway 组件是SpringCloud 组件中的网关组件,主要是解决路由转发的问题;跟nginx有点类似,区别是nginx多用在前端上,gateway用在后端上。当然gateway的功能不止路由转发,还可以用来:

1.针对所有请求做统一鉴权、限流、熔断、日志;

2.协议转化,针对后端多种协议可以在网关层统一处理后以http对外服务;

3.统一错误代码处理(跟springboot统一错误处理配置一样);

一、配置说明

gateway的配置文件是其使用的核心。

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Path=/table-service/**
          filters:
            - StripPrefix=1

字段说明:

id:自定义路由的ID;

uri:目标服务器地址,同时支持 URI(http://ip:port/route) 和 lb(lb://应用注册服务名) 方式,推荐使用lb方式;

predicates:路由条件,根据匹配结果决定是否执行该请求路由;

filters:过滤规则,包含 pre 和 post 过滤,其中 StripPrefix=1 表示根据请求时去掉URL路径的第一个前缀。

二、路由条件配置说明

即 predicates 配置项,支持多种规则:

1. 指定时间规则匹配路由

时间的书写必须是ZoneDateTime格式。

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - After=2022-07-20T10:25:00.000+08:00[Asia/Shanghai]

有三种规则:

After:指定时间之后转发到该服务;

Before:指定时间之前转发到该服务;

Between:两个时间之前转发到该服务,两个时间之间用逗号隔开;

2. Cookie 匹配路由

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Cookie=cho,123

上述配置表示请求时 Cookie 必须携带 cho=123 键值对才能转发到该服务;逗号前表示键值,逗号后表示该键对应的值,该值是个正则表达式。

3. Header 匹配路由

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Header=cho,123

上述配置表示请求时 header 必须携带 cho=123 键值对才能转发到该服务;逗号前表示键值,逗号后表示该键对应的值,该值是个正则表达式。

4. Host 匹配路由

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Host=127.0.0.1,localhost

上述配置表示请求时 Host 必须携带 127.0.0.1,localhost 中的任何一个值才能转发到该服务;匹配多值时用逗号隔开,并且支持星号(*)做域名通配符。

5. 请求方法匹配路由

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Method=POST,GET

上述配置表示请求时只有 GET 和 POST 方法才能转发到该服务;匹配多值时用逗号隔开。

6. 请求路径匹配路由

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Path=/table/**

该方式是使用最多的。/* 表示单层路径匹配,/** 表示多层路径匹配。

三、过滤配置说明

即 filters 配置项,支持多种配置:

1.  AddRequestParameters GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Path=/table/**
          filters:
            - AddRequestParameter=foo,bar

上述配置会对走该路由的所有请求都加上 foo=bar 参数。

 2.  AddResponseHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Path=/table/**
          filters:
            - AddResponseHeader=foo,bar

上述配置会对走该路由的所有请求的返回都加上响应头 foo=bar 。

 3.  RequestRateLimiter GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Path=/table/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20

这个过滤器是基于令牌桶实现的,replenishRate 表示令牌填充速度,burstCapacity 表示令牌桶容量;限流用的,需要集成redis才行。限流的使用略复杂,建议单独研究。

  4.  Retry GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Path=/table/**
          filters:
            - name: Retry
              args:
                retries: 3
                status: 503

总共涉及4个参数:

retries:重试次数;

status:http 请求返回的状态码,上述配置表示服务端返回503时发起重试;

methods:指定请求类型才会发起重试;

series:配置错误码段,表示符合状态码才发起重试,默认SERVER_ERROR(5),即 5xx 段状态码才会发起重试;如果 series 配置了错误码,但 status 缺省,则仍然匹配 series 进行重试。

四、自定义 Filter

自定义 filter 有两个,GlobalFilter 和 GatewayFilter ;GlobalFilter 对全局生效,GatewayFilter 只对配置了的才生效。

1. 自定义 GlobalFilter

可以存在多个 GlobalFilter,执行顺序由 getOrder() 控制,值越小执行越靠前。

@Slf4j
@Service
public class GatewayGlobalFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        
        log.info("pre action..."); //请求到路由前的操作...
        
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            log.info("post action..."); //请求返回后的操作...
        }));
    }

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

 2. 自定义 gatewayFilter

@Slf4j
@Service
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.CustomConfig> {

    public CustomGatewayFilterFactory() {
        super(CustomConfig.class);
    }

    @Override
    public GatewayFilter apply(CustomConfig config) {
        return ((exchange, chain) -> {
            String name = config.getName();

            log.info("config name:{}", name);
            log.info("pre action...");

            if (name.equals("123")) {                           // 使用config值的样例
                return exchange.getResponse().setComplete();    // 不返回任何信息
            }

            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("post action...");
            }));
        });
    }

    public static class CustomConfig {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

上述对应的配置文件:

spring:
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Path=/table/**
          filters:
            - name: Custom
              args:
                name: 123

几点注意:

1. 类名一般遵循以 GatewayFilterFactory 结尾,所以默认情况下过滤器 name 会采用该自定义类名的前缀,这里配置 name=Custom;或者类名完全不遵循上述规则,,配置时name为类全名;

2. 在 apply 方法中,同时包含 Pre 和 Post 过滤;在 then 方法中是请求执行结束之后的处置;

3. CustomConfig 是一个配置类,其属性值可在配置文件 args 下一层进行配置;

3. 补充

以下是请求不满足条件时的 json 返回。

// msg 是个 json 字符串
DataBuffer bodyDataBuffer =response.bufferFactory().wrap(msg.getBytes(StandardCharsets.UTF_8));
return response.writeWith(Mono.just(bodyDataBuffer));

五、整个 demo

1. 本地起一个eureka的注册中心(也可以用nacos等其他的注册中心)

端口:9099

本片代码不是该博客核心,忽略。

2. 起一个gateway的client注册到eureka

依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>eureka-gateway</artifactId>
    <version>1.0.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/>
    </parent>

    <dependencies>

        <!--在springboot的pom文件中,该依赖已经集成了springMVC等web启动器,不需要再添加spring-boot-starter-web 依赖了-->
        <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.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2020.0.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

启动类:

@EnableEurekaClient
@SpringBootApplication
public class GatewayServer {
    public static void main(String[] args) {
        SpringApplication.run(GatewayServer.class, args);
    }
}

配置文件:

server:
  port: 8999

spring:
  application:
    name: gateway-service
  cloud:
    gateway:
      routes:
        - id: table-service
          uri: lb://table-service
          predicates:
            - Path=/table-service/**
          filters:
            - StripPrefix=1

        - id: table-service
          uri: lb:ws://table-service    #这是websocket转发的配置
          predicates:
            - Path=/table-socket/**
          filters:
            - StripPrefix=1

eureka:
  instance:
    lease-expiration-duration-in-seconds: 10
    lease-renewal-interval-in-seconds: 5
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
  client:
    service-url:
      defaultZone: http://user:passwd@localhost:9099/eureka/

猜你喜欢

转载自blog.csdn.net/qingquanyingyue/article/details/125921909