分布式微服务 - 3.服务网关 - 4.Gateway

分布式微服务 - 3.服务网关 - 4.Gateway

项目示例:

  • 项目示例 - 3.服务网关 - 3.Gateway

内容提要:

  • 基本使用:配置方式、代码方式
  • 内置断言、自定义断言
  • 内置局部过滤器、自定义内置和全局过滤器

文档:

基本使用

配置方式

  1. 引入依赖:使用gateway依赖时,不能同时引入spring-boot-starter-web依赖。gateway配合nacos使用别名进行路由,需要使用负载均衡(而nacos依赖不包含),因此要单独引入loadbalancer依赖
xml 复制代码
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
  1. application.yml配置
yml 复制代码
spring:
  cloud:
    gateway:
      discovery:
        locator:
          # 从服务注册中心根据别名来进行路由
          enabled: true
      routes:
        # 路由Id,自定义,唯一即可
        - id: nacos-provider-test
          # 成功匹配后,要转换成的路由地址(配合服务注册中心使用别名),需要负载均衡依赖
          uri: lb://nacos-provider
          # 成功匹配后,要转换成的路由地址(不配合服务注册中心)
          #uri: http://localhost:8001
          # 断言
          predicates:
            # 路径匹配的进行路由
            - Path=/**

代码方式

java 复制代码
@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator myRouteLocator(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("nacos-provider-test", r -> r.path("/**").uri("lb://nacos-provider"));
        return routes.build();
    }

}

路由配置

路由是由ID、URI、一系列的断言和过滤器组成的。断言可以匹配请求中的所有内容,如果请求与断言相匹配则进行路由。URI是进行路由时,要转换成的路由地址。在满足断言之后,过滤器可以修改向URI发送的请求和返回的响应。

断言

gateway本身内置许多断言(RoutePredicateFactory接口的实现类),多个断言可以组合使用。

当一个请求可以满足多个路由的断言时,会按定义的顺序找第一个满足断言的路由。

内置断言

内置断言中用到的时间格式可以用代码ZonedDateTime.now() 获取,也可以指定时间区域ZonedDateTime.now(ZoneId.of("Asia/Shanghai"))

常用内置断言

  • Path
    • 请求满足路径正则表达式则匹配
    • 如:Path=/product-serv/segment,/server-b/**
  • Method
    • 请求满足指定请求方式则匹配
    • 如:Method=GET,POST
  • Cookie
    • 请求cookie中存在指定key且value满足正则表达式则匹配
    • 如:Cookie=key, valueReg
  • Header
    • 请求头中存在指定key且value满足正则表达式则匹配
    • 如:Header=X-Request-Id, \d+
  • Query
    • 请求带有指定参数且value满足正则表达式则匹配
    • 如:Query=name, fly
  • RemoteAddr
    • 请求的ip在指定ip/mask内则匹配
    • 如:RemoteAddr=192.168.1.0/24
  • Host
    • 请求的host满足正则表达式则匹配
    • 如:Host=localhost:8080,localhost:8081
  • After
    • 请求时间在指定时间之后则匹配,可用于在未来指定时间上线服务
    • 如:After=2024-01-01T23:59:59.123+08:00[Asia/Shanghai]
  • Before
    • 请求时间在指定时间之前则匹配,可用于服务在指定时间内可访问
    • 如:Before=2024-01-01T23:59:59.123+08:00[Asia/Shanghai]
  • Between
    • 请求时间在指定时间之间则匹配,可用于服务在指定时间内可访问
    • 如:Between=2024-01-01T23:59:59.123+08:00[Asia/Shanghai], 2024-01-02T23:59:59.123+08:00[Asia/Shanghai]
自定义断言
  1. 创建类并@Component注入:类名要求是XxxRoutePredicateFactory(配置文件中使用断言时,断言名为Xxx)
java 复制代码
@Component
public class CustomRoutePredicateFactory
  1. 创建静态内部类:用于接收参数,因此要有属性值和对应的getter和setter
java 复制代码
    @Getter
    @Setter
    public static class Config {
        private String key;
        private String value;
    }
  1. 继承抽象类:继承断言工厂类AbstractRoutePredicateFactory并确定泛型为内部类
java 复制代码
@Component
public class CustomRoutePredicateFactory extends AbstractRoutePredicateFactory<CustomRoutePredicateFactory.Config>
  1. 构造方法
java 复制代码
    public CustomRoutePredicateFactory() {
        super(Config.class);
    }
  1. 重写读配置文件方法:方法读取配置文件的参数值,赋值到内部类中的属性上(顺序必须与yml文件中的配置顺序对应)
java 复制代码
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("key", "value");
    }
  1. 重写apply方法:返回true路由成功,返回false返回404(serverWebExchange可以获取很多内容)
java 复制代码
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                List<String> strings = serverWebExchange.getRequest().getHeaders().get(config.key);
                if (strings==null || strings.isEmpty())
                    return false;
                return config.value.equals(strings.get(0));
            }
        };
    }
  1. yml文件中配置断言
yml 复制代码
Custom=test, a

过滤器

过滤器分为局部过滤器和全局过滤器,局部过滤器仅在配置的路由上起效,而全局过滤器对所有的路由都起效。

内置局部过滤器

常用内置过滤器

  • StripPrefix

    • 转换成路由之前,去掉URL中前面几节
    • 如:StripPrefix=1
  • PrefixPath

    • 给请求路径path添加前缀
    • 如:PrefixPath=/nacos
  • AddRequestParameter

    • 添加请求参数
    • 如:AddRequestParameter=name,test
  • RemoveRequestParameter

    • 删除请求参数
    • 如:RemoveRequestParameter=name
  • AddRequestHeader

    • 在请求头上添加参数
    • 如:AddRequestHeader=key,value
  • SetRequestHeader

    • 修改请求头上指定参数的值,参数不存在时创建
    • 如:SetRequestHeader=myHeader, test
  • RemoveRequestHeader

    • 删除请求头上的指定参数
    • 如:RemoveRequestHeader=MyHeader
  • AddResponseHeader

    • 在响应头上添加参数
    • 如:AddRequestHeader=key,value
  • SetResponseHeader

    • 修改响应头上指定参数的值,参数不存在时创建
    • 如:SetResponseHeader=addHeader, test
  • RewriteResponseHeader

    • 修改响应头上指定参数的值,第一个参数是key,第二个参数是正则表达式匹配修改前的值,第三个参数是修改后的值
    • 如:RewriteResponseHeader=addHeader,test1,test
  • RemoveResponseHeader

    • 删除响应头上的指定参数
    • 如:RemoveResponseHeader=addHeader
  • SetStatus

    • 设置返回的响应码
    • 如:SetStatus=500
  • RedirectTo

    • 重定向,两个参数分别是重定向300系列状态码和URL
    • 如:RedirectTo=302, https://www.baidu.com
  • RewritePath

    • 重写请求路径
    • 如:RewritePath=/test1/?(?.*), /nacos/${segment}
自定义局部过滤器
  1. 创建类并@Component注入:类名要求是XxxGatewayFilterFactory(配置文件中使用过滤器时,过滤器名为Xxx)
java 复制代码
@Component
public class CustomGatewayFilterFactory
  1. 创建静态内部类:用于接收参数,因此要有属性值和对应的getter和setter
java 复制代码
    @Getter
    @Setter
    public static class Config {
        private String key;
        private String value;
    }
  1. 继承抽象类:继承过滤器工厂类AbstractGatewayFilterFactory并确定泛型为内部类
java 复制代码
@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config>
  1. 构造方法
java 复制代码
    public CustomRoutePredicateFactory() {
        super(Config.class);
    }
  1. 重写读配置文件方法:方法读取配置文件的参数值,赋值到内部类中的属性上(顺序必须与yml文件中的配置顺序对应)
java 复制代码
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("key", "value");
    }
  1. 重写apply方法:可以在chain.filter(exchange).then之前操作request,之后操作response(serverWebExchange可以获取很多内容)
java 复制代码
    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // pre操作
                return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    // 异步post操作
                }));
            }
        };
    }
  1. yml文件中配置断言
yml 复制代码
Custom=test, a
自定义全局过滤器
  1. 创建GlobalFilter、Ordered接口实现类并@Component注入
java 复制代码
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered
  1. 重写getOrder方法:方法返回的值越小,过滤器的优先级越高
java 复制代码
    @Override
    public int getOrder() {
        return 0;
    }
  1. 重写filter方法
java 复制代码
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // pre操作
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            // 异步post操作
        }));
    }
相关推荐
这周也會开心1 分钟前
RabbitMQ知识点
分布式·rabbitmq
Victor3561 分钟前
MongoDB(2)MongoDB与传统关系型数据库的主要区别是什么?
后端
JaguarJack2 分钟前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端·php·服务端
BingoGo3 分钟前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端
Victor3564 分钟前
MongoDB(3)什么是文档(Document)?
后端
岁岁种桃花儿1 小时前
Kafka从入门到上天系列第三篇:基础架构推演+基础组件图形推演
分布式·kafka
牛奔2 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
想用offer打牌7 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX8 小时前
服务异步通信
开发语言·后端·微服务·ruby