SpringCloud 系列之 gateway 网关

本文介绍了SpringCloudGateway在Spring生态系统中的应用,涵盖其工作原理、在微服务架构中的位置,以及路由、断言和过滤器的核心概念。通过详细配置示例,展示了如何设置路由规则和自定义断言和过滤器,以实现流量控制和安全等功能。
摘要由CSDN通过智能技术生成

在这里插入图片描述
提供了一个构建在 Spring 生态系统之上的 API 网关,包括:Spring 6、Spring Boot 3 和 Project Reactor。Spring Cloud Gateway 旨在提供一种简单而有效的方法来路由到 API 并为其提供横切关注点,例如:安全性、监控/指标和弹性。

官网:https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/

1. 工作原理

客户端向 Spring Cloud Gateway 发出请求。如果网关处理程序映射确定请求与路由匹配,则会将其发送到网关 Web 处理程序。该处理程序通过特定于请求的过滤器链运行请求。过滤器被虚线分开的原因是过滤器可以在发送代理请求之前和之后运行逻辑。执行所有“预”过滤器逻辑。然后发出代理请求。发出代理请求后,将运行“post”过滤器逻辑。
在这里插入图片描述

2. 微服务中网关的位置

在这里插入图片描述

3. 官网的作用

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

4. 三大核心

在这里插入图片描述

  • 路由:网关的基本构建块。它由 ID、目标 URI、谓词集合和过滤器集合定义。如果聚合谓词为真,则匹配路由。
  • 断言:这是一个Java 8 函数谓词。输入类型是Spring FrameworkServerWebExchange。这使您可以匹配 HTTP 请求中的任何内容,例如标头或参数。
  • 过滤:这些是GatewayFilter使用特定工厂构建的实例。在这里,您可以在发送下游请求之前或之后修改请求和响应。

5. 入门案例

5.1 创建SpringBoot工程

在这里插入图片描述

5.2 添加pom文件

<!--gateway-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

5.3 添加 yml 内容

spring:
  application:
    name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  cloud:
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service           # lb:服务名
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由

5.4 修改启动类

@SpringBootApplication
@EnableDiscoveryClient //服务注册和发现
public class Main9527
{
    public static void main(String[] args)
    {
        SpringApplication.run(Main9527.class,args);
    }
}

5.5 测试

以上一个简单的 gateway 网关服务搭建完成。启动服务,访问 http://localhost:9527/pay/gateway/get/1。即可访问到cloud-payment-service服务的方法。

6. 核心特性

接下来,我们对 gateway 的三大核心进行详细讲解。

6.1 路由 Route-URI

在 yml 配置文件中 uri 属性,在日常应用中都不会写死 ip:port,这样无法做到动态获取,而是配合注册中心使用,如:

  cloud:
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service           # lb:服务名
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由

在案例中,uri 写的是 lb://注册到注册中心的微服务名

6.2 断言 Predicate

6.2.1 断言配置方式

配置断言有两种方式:快捷方式(Shortcut Configuration)和完全扩展的参数(Fully Expanded Arguments)。

  1. 快捷方式:配置由过滤器名称识别,后跟等号 ( =),然后是用逗号 ( ,) 分隔的参数值。
spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Cookie=mycookie,mycookievalue

Cookie使用两个参数定义 Route Predicate Factory:cookie 名称mycookie和要匹配的值mycookievalue

  1. 完全扩展的参数看起来更像是带有名称/值对的标准 yaml 配置。通常,会有name和args关键字。键args是用于配置谓词或过滤器的键值对的映射。
spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue
6.2.2 内置的断言
  1. The After Route Predicate Factory:匹配指定日期时间之后发生的请求
spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2024-03-27T20:45:49.677486+08:00[Asia/Shanghai]

时间获取方式:ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区

  1. The Before Route Predicate Factory:匹配在指定的之前发生的请求
spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: https://example.org
        predicates:
        - Before=2024-03-27T20:45:49.677486+08:00[Asia/Shanghai]
  1. The Between Route Predicate Factory:匹配指定两个日期之间发生的请求
spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: https://example.org
        predicates:
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
  1. The Cookie Route Predicate Factory:匹配具有给定名称且其值与正则表达式匹配的 cookie
spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://example.org
        predicates:
        - Cookie=chocolate, ch.p

匹配带 cookie 且 cookie 的名称为chocolate,cookie 的值为ch.p 的请求

  1. The Header Route Predicate Factory:与具有给定名称且其值与正则表达式匹配的标头匹配
spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

如果请求的请求头中具有名为 X-Request-Id 其值与 \d+ 正则表达式匹配的标头(即,它具有一位或多位数字的值),则此路由匹配

  1. The Host Route Predicate Factory:匹配参数中的主机地址
spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

若请求是 curl http://localhost:9527/pay/gateway/get/3 -H "Host:java.somehost.org" 则请求匹配。

  1. The Method Route Predicate Factory:匹配请求的 http 方法
spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://example.org
        predicates:
        - Method=GET,POST
  1. The Path Route Predicate Factory:匹配请求路径
spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment}

若请求地址是:/red/1 则匹配
这要是我们常用的匹配方式

  1. The Query Route Predicate Factory:匹配请求参数
spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=username, \d+

参数名username并且值还要是整数才能路由

  1. The RemoteAddr Route Predicate Factory:匹配 ip 地址
spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法

在这里插入图片描述

大白话翻译:如 192.168.31.1/24 此 ip 一共 32 位,用符号.间隔,每个间隔是 8 位,后面的/24表示前 24 位不变,也就是 ip 范围是 192.168.31.1~192.168.31.255

  1. The Weight Route Predicate Factory:按照权重转发流量
spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

该路由会将约 80% 的流量转发到Weighthigh.org,将约 20% 的流量转发到Weightlow.org

  1. The XForwarded Remote Addr Route Predicate Factory:根据 HTTP 标头过滤请求X-Forwarded-For
spring:
  cloud:
    gateway:
      routes:
      - id: xforwarded_remoteaddr_route
        uri: https://example.org
        predicates:
        - XForwardedRemoteAddr=192.168.1.1/24

若请求头包含 X-Forwarded-For 且 值为192.168.1.1/24,则匹配

6.2.3 自定义断言
6.2.3.1 自定义断言方式
  1. 继承AbstractRoutePredicateFactory
  2. 实现RoutePredicateFactory接口
  3. 自定义断言类型必须以RoutePredicateFactory结尾
6.2.3.2 自定义断言步骤
  1. 新建类,名称以RoutePredicateFactory后缀,并且继承AbstractRoutePredicateFactory
  2. 重写 apply 方法
  3. 新建 apply 方法需要的静态内部类Config
  4. 新增空参构造,调用 super
  5. 重写shortcutFieldOrder方法,为了支持快捷方式
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{
    public MyRoutePredicateFactory()
    {
        super(MyRoutePredicateFactory.Config.class);
    }

    @Validated
    public static class Config{
        @Setter
        @Getter
        @NotEmpty
        private String userType; //钻、金、银等用户等级
    }

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config)
    {
        return new Predicate<ServerWebExchange>()
        {
            @Override
            public boolean test(ServerWebExchange serverWebExchange)
            {
                //检查request的参数里面,userType是否为指定的值,符合配置就通过
                String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");

                if (userType == null) return false;

                //如果说参数存在,就和config的数据进行比较
                if(userType.equals(config.getUserType())) {
                    return true;
                }

                return false;
            }
        };
    }
	@Override
	public List<String> shortcutFieldOrder() {
		return Collections.singletonList("userType");
	}
}

使用:

spring:
  cloud:
    gateway:
      routes:
      - id: mytest
        uri: https://example.org
        predicates:
         - My=diamond   #快捷写法
            #- name: My # 完全扩展写法
            #  args:
            #    userType: diamond

6.3 过滤器 Filter

路由过滤器允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。路由过滤器的范围仅限于特定路由。Spring Cloud Gateway 包含许多内置的 GatewayFilter Factory。

只挑选一部分讲解,其他的可以参考官网
https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/#gatewayfilter-factories

gateway 内置了很多过滤器,大概可以分成几大类:请求头相关、请求参数相关、相应头相关、前缀和路径相关、其他。

6.3.1 请求头相关

  1. The AddRequestHeader GatewayFilter Factory
    在请求头添加参数:
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-red, blue

也可以使用请求参数

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment}
        filters:
        - AddRequestHeader=X-Request-Red, Blue-{segment}

  1. The RemoveRequestHeader GatewayFilter Factory
    删除请求头中的参数
spring:
  cloud:
    gateway:
      routes:
      - id: removerequestheader_route
        uri: https://example.org
        filters:
        - RemoveRequestHeader=X-Request-Foo

  1. The SetRequestHeader GatewayFilter Factory
    将请求头中的参数值更新
spring:
  cloud:
    gateway:
      routes:
      - id: setrequestheader_route
        uri: https://example.org
        filters:
        - SetRequestHeader=X-Request-Red, Blue

也可以使用请求参数

spring:
  cloud:
    gateway:
      routes:
      - id: setrequestheader_route
        uri: https://example.org
        predicates:
        - Host: {segment}.myhost.org
        filters:
        - SetRequestHeader=foo, bar-{segment}

6.3.2 请求参数相关

  1. The AddRequestParameter GatewayFilter Factory
    添加请求参数
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://example.org
        filters:
        - AddRequestParameter=red, blue

也可以设置请求的其他参数或者host 中的参数

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://example.org
        predicates:
        - Host: {segment}.myhost.org
        filters:
        - AddRequestParameter=foo, bar-{segment}
  1. The RemoveRequestParameter GatewayFilter Factory
    删除请求参数
spring:
  cloud:
    gateway:
      routes:
      - id: removerequestparameter_route
        uri: https://example.org
        filters:
        - RemoveRequestParameter=red

6.3.3 相应头相关

  1. The AddResponseHeader GatewayFilter Factory
    添加响应头参数
spring:
  cloud:
    gateway:
      routes:
      - id: add_response_header_route
        uri: https://example.org
        filters:
        - AddResponseHeader=X-Response-Red, Blue

也可以使用响应头其他的参数

spring:
  cloud:
    gateway:
      routes:
      - id: add_response_header_route
        uri: https://example.org
        predicates:
        - Host: {segment}.myhost.org
        filters:
        - AddResponseHeader=foo, bar-{segment}
  1. The RemoveResponseHeader GatewayFilter Factory
    删除响应头参数
spring:
  cloud:
    gateway:
      routes:
      - id: removeresponseheader_route
        uri: https://example.org
        filters:
        - RemoveResponseHeader=X-Response-Foo
  1. The SetResponseHeader GatewayFilter Factory
    设置相应头参数
spring:
  cloud:
    gateway:
      routes:
      - id: setresponseheader_route
        uri: https://example.org
        filters:
        - SetResponseHeader=X-Response-Red, Blue
spring:
  cloud:
    gateway:
      routes:
      - id: setresponseheader_route
        uri: https://example.org
        predicates:
        - Host: {segment}.myhost.org
        filters:
        - SetResponseHeader=foo, bar-{segment}

6.3.4 前缀和路径相关

  1. The PrefixPath GatewayFilter Factory:添加路径前缀
spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - PrefixPath=/mypath

若请求是/hello则发送至/mypath/hello
2. The RedirectTo GatewayFilter Factory:重定向

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - RedirectTo=302, https://acme.org

请求执行 302 重定向到https://acme.org,status 必须是 3xx

  1. The SetPath GatewayFilter Factory:访问路径修改
spring:
  cloud:
    gateway:
      routes:
      - id: setpath_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment}
        filters:
        - SetPath=/{segment}

对于的请求路径/red/blue,在发出下游请求之前将路径设置为/blue

6.3.5 其他

  1. Default Filters:默认过滤自动应用于所有路由
spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Red, Default-Blue
      - PrefixPath=/httpbin

以上配置说明:所有请求的相应头中添加X-Response-Default-Red的键,值为Default-Blue;所有请求的路径前缀添加/httpbin

6.3.6 自定义过滤器
6.3.6.1 自定义全局过滤器

实现GlobalFilter接口,重写filter方法即可。

@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered
{

    /**
     * 数字越小优先级越高
     * @return
     */
    @Override
    public int getOrder()
    {
        return 0;
    }

    private static final String BEGIN_VISIT_TIME = "begin_visit_time";//开始访问时间
    /**
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //先记录下访问接口的开始时间
        exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());

        return chain.filter(exchange).then(Mono.fromRunnable(()->{
            Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);
            if (beginVisitTime != null){
                log.info("访问接口主机: " + exchange.getRequest().getURI().getHost());
                log.info("访问接口端口: " + exchange.getRequest().getURI().getPort());
                log.info("访问接口URL: " + exchange.getRequest().getURI().getPath());
                log.info("访问接口URL参数: " + exchange.getRequest().getURI().getRawQuery());
                log.info("访问接口时长: " + (System.currentTimeMillis() - beginVisitTime) + "ms");
                log.info("我是美丽分割线: ###################################################");
                System.out.println();
            }
        }));
    }

}
6.3.6.2 自定义条件过滤器
  1. 继承AbstractGatewayFilterFactory类
  2. 重写apply方法
  3. 重写shortcutFieldOrder方法
  4. 定义内部静态类Config
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config>
{
    public MyGatewayFilterFactory()
    {
        super(MyGatewayFilterFactory.Config.class);
    }


    @Override
    public GatewayFilter apply(MyGatewayFilterFactory.Config config)
    {
        return new GatewayFilter()
        {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
            {
                ServerHttpRequest request = exchange.getRequest();
                System.out.println("进入了自定义网关过滤器MyGatewayFilterFactory,status:"+config.getStatus());// abc
                if(request.getQueryParams().containsKey("zhang")){
                    return chain.filter(exchange);
                }else{
                    exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
                    return exchange.getResponse().setComplete();
                }
            }
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("status");
    }

    public static class Config
    {
        @Getter@Setter
        private String status;//设定一个状态值/标志位,它等于多少,匹配和才可以访问
    }
}

使用:

spring:
  cloud:
    gateway:
      routes:
      - id: customFilter
        uri: https://example.org
        filters:
        - My=abc
        #- name:My		# 全名称
        #  args:
        #    status:abc

请求:http://ip:port/xxx?zhang=abc

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值