【微服务架构】SpringCloud Alibaba(六):SpringCloud Gateway网关(过滤器工厂配置)

文章目录

  • 一、SpringCloud Alibaba
    • 1、核心组件
    • 2、优势
    • 3、应用场景
  • 二、过滤器工厂( GatewayFilter Factories)配置
    • 1、内置过滤器
      • 1.1 AddRequestHeader 过滤工厂
      • 1.2 AddRequestParameter 过滤工厂
      • 1.3 AddResponseHeader 过滤工厂
      • 1.4 DedupeResponseHeader 过滤工厂
      • 1.5 PrefixPath 过滤工厂
      • 1.6 PreserveHostHeader 过滤工厂
      • 1.7 RequestRateLimiter 过滤工厂
      • 1.8 RedirectTo 过滤工厂
      • 1.9 RemoveHopByHopHeadersFilter 过滤工厂
      • 1.10 RemoveRequestHeader 过滤工厂
      • 1.11 RemoveResponseHeader 过滤工厂
      • 1.12 RewritePath 过滤工厂
      • 1.13 RewriteResponseHeader 过滤工厂
      • 1.14 SaveSession 过滤工厂
      • 1.15 SecureHeaders 过滤工厂
      • 1.16 SetPath 过滤工厂
      • 1.17 SetResponseHeader 过滤工厂
      • 1.18 SetStatus 过滤工厂
      • 1.19 StripPrefix 过滤工厂
      • 1.20 Retry 过滤工厂
      • 1.21 RequestSize 过滤工厂
      • 1.22 默认过滤器工厂
    • 2、AddRequestHeader 过滤工厂
    • 3、自定义过滤器
      • 3.1 过滤器生命周期
      • 3.2 自定义过滤器工厂的方式
      • 3.3 核心API
      • 3.4 编写一个过滤器工厂
    • 4、全局过滤器
      • 4.1 **LoadBalancerClientFilter**
      • 4.2 自定义过滤器

在这里插入图片描述
个人主页:道友老李
欢迎加入社区:道友老李的学习社区

一、SpringCloud Alibaba

Spring Cloud Alibaba是阿里巴巴提供的一站式微服务解决方案,是Spring Cloud体系中的一个重要分支,它将阿里巴巴在微服务领域的实践经验和开源技术进行了整合,为开发者提供了一系列便捷的工具和组件,用于构建分布式微服务应用。以下是其详细介绍:

1、核心组件

  • Nacos:用于服务注册与发现以及配置管理。它可以帮助微服务实例自动注册到注册中心,并能够动态获取配置信息,使应用程序能够灵活地应对配置的变化,无需重启服务。
  • Sentinel:主要用于流量控制、熔断降级等功能。它可以保护微服务免受高并发、流量异常等情况的影响,确保系统在压力下能够稳定运行,避免因个别服务出现问题而导致整个系统崩溃。
  • RocketMQ:是一款高性能、高可靠的分布式消息队列。它在微服务架构中常用于实现异步消息传递、解耦系统组件之间的依赖关系,从而提高系统的整体性能和可扩展性。
  • Seata:致力于提供分布式事务解决方案,确保在分布式系统中数据的一致性。它通过对事务的协调和管理,使得多个微服务之间在进行数据交互时能够遵循ACID原则。

2、优势

  • 一站式解决方案:涵盖了微服务架构中的多个关键领域,包括服务治理、配置管理、流量控制、分布式事务等,开发者无需再从多个不同的开源项目中进行整合,大大降低了微服务架构的搭建和维护成本。
  • 与Spring Cloud生态的深度集成:基于Spring Cloud的编程模型和规范进行开发,使得熟悉Spring Cloud的开发者能够快速上手并轻松集成到现有的Spring Cloud项目中,充分利用Spring Cloud的各种特性和优势。
  • 阿里巴巴的技术实力和实践经验支持:得益于阿里巴巴在大规模分布式系统开发和运营方面的丰富经验,Spring Cloud Alibaba的组件经过了实际生产环境的考验,具有较高的稳定性、性能和可扩展性,能够应对各种复杂的业务场景和高并发流量。

3、应用场景

  • 电商系统:在电商业务中,存在多个微服务,如商品服务、订单服务、库存服务等。Spring Cloud Alibaba可以通过Nacos进行服务注册与发现,使用Sentinel对各个服务的流量进行控制,利用RocketMQ实现异步消息通知,比如下单成功后异步通知库存服务扣减库存,通过Seata保证分布式事务的一致性,确保订单和库存等数据的准确性。
  • 金融系统:金融领域对数据一致性和系统稳定性要求极高。Spring Cloud Alibaba的Seata可以确保在多个金融业务操作之间的分布式事务一致性,如转账操作涉及到两个不同账户服务之间的资金变动。Nacos可以提供配置管理,方便对金融业务的各种配置参数进行动态调整,Sentinel则可以防止因突发的高并发交易对系统造成冲击。
  • 物联网(IoT)平台:物联网场景中,大量的设备会产生实时数据并上传到云端。Spring Cloud Alibaba可以通过Nacos管理各个物联网服务的注册与发现,使用RocketMQ接收和处理大量的设备数据消息,进行异步处理和分发。Sentinel可以对物联网服务的流量进行控制,防止因设备数据突发增长导致系统过载。

二、过滤器工厂( GatewayFilter Factories)配置

SpringCloudGateway 内置了很多的过滤器工厂,我们通过一些过滤器工厂可以进行一些业务逻辑处理器,比如添加剔除响应头,添加去除参数等

官网:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories

1、内置过滤器

1.1 AddRequestHeader 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-Foo, Bar

为原始请求添加名为 X-Request-Foo ,值为 Bar 的请求头。

1.2 AddRequestParameter 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://example.org
        filters:
        - AddRequestParameter=foo, bar

为原始请求添加请求参数 foo=bar

1.3 AddResponseHeader 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: add_response_header_route
        uri: https://example.org
        filters:
        - AddResponseHeader=X-Response-Foo, Bar

添加名为 X-Request-Foo ,值为 Bar 的响应头。

1.4 DedupeResponseHeader 过滤工厂

Spring Cloud Greenwich SR2提供的新特性,低于这个版本无法使用。

强烈建议阅读一下类org.springframework.cloud.gateway.filter.factory.DedupeResponseHeaderGatewayFilterFactory上的注释,比官方文档写得还好。

spring:
  cloud:
    gateway:
      routes:
      - id: dedupe_response_header_route
        uri: https://example.org
        filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_FIRST

剔除重复的响应头。

举个例子:

我们在Gateway以及微服务上都设置了CORS(解决跨域)header,如果不做任何配置,请求 -> 网关 -> 微服务,获得的响应就是这样的:

Access-Control-Allow-Credentials: true, true
Access-Control-Allow-Origin: https://www.dylledu.com, https://www.dylledu.com

也就是Header重复了。要想把这两个Header去重,只需设置成如下即可。

filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

也就是说,想要去重的Header如果有多个,用空格分隔即可;

去重策略:

RETAIN_FIRST: 默认值,保留第一个值
RETAIN_LAST: 保留最后一个值
RETAIN_UNIQUE: 保留所有唯一值,以它们第一次出现的顺序保留

1.5 PrefixPath 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - PrefixPath=/mypath

为匹配的路由添加前缀。例如:访问 ${GATEWAY_URL}/hello 会转发到 https://example.org/mypath/hello

1.6 PreserveHostHeader 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: preserve_host_route
        uri: https://example.org
        filters:
        - PreserveHostHeader

如果不设置,那么名为 Host 的Header由Http Client控制;如果设置了,那么会设置一个请求属性(preserveHostHeader=true),路由过滤器会检查从而去判断是否要发送原始的、名为Host的Header。

1.7 RequestRateLimiter 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20

1.8 RedirectTo 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        # 配置成HTTP状态码, URL的形式
        - RedirectTo=302, http://www.dyll.com

  • HTTP状态码应该是HTTP状态码300序列,例如301
  • URL必须是合法的URL,并且该值会作为名为 Location 的Header。

上面配置表达的意思是: ${GATEWAY_URL}/hello 会重定向到 https://ecme.org/hello ,并且携带一个 Location:http://www.dyll.com 的Header。

1.9 RemoveHopByHopHeadersFilter 过滤工厂

spring.cloud.gateway.filter.remove-hop-by-hop.headers: Connection,Keep-Alive

移除转发请求的Header,多个用 , 分隔。默认情况下,移除如下Header。这些Header是由 IETF 组织规定的。

  • Connection
  • Keep-Alive
  • Proxy-Authenticate
  • Proxy-Authorization
  • TE
  • Trailer
  • Transfer-Encoding
  • Upgrade

1.10 RemoveRequestHeader 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: removerequestheader_route
        uri: https://example.org
        filters:
        - RemoveRequestHeader=X-Request-Foo

原始请求删除名为 X-Request-Foo 的请求头。

1.11 RemoveResponseHeader 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: removeresponseheader_route
        uri: https://example.org
        filters:
        - RemoveResponseHeader=X-Response-Foo

删除名为 X-Request-Foo 的响应头。

1.12 RewritePath 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://example.org
        predicates:
        - Path=/foo/**
        filters:
        # 配置成原始路径正则, 重写后的路径的正则
        - RewritePath=/foo/(?>.*), /$\{segment}

重写请求路径。如上配置,访问 /foo/bar 会将路径改为 /bar 再转发,也就是会转发到 https://example.org/bar 。需要注意的是,由于YAML语法,需用 $\ 替换 $$

1.13 RewriteResponseHeader 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: rewriteresponseheader_route
        uri: https://example.org
        filters:
        - RewriteResponseHeader=X-Response-Foo, password=[^&]+, password=***

如果名为 X-Response-Foo 的响应头的内容是 /42?user=ford&password=omg!what&flag=true,则会被修改为 /42?user=ford&password=***&flag=true

1.14 SaveSession 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: save_session
        uri: https://example.org
        predicates:
        - Path=/foo/**
        filters:
        - SaveSession

在转发到后端微服务请求之前,强制执行 WebSession::save 操作。用在那种像 Spring Session 延迟数据存储(笔者注:数据不是立刻持久化)的,并希望在请求转发前确保session状态保存情况。

如果你将 Spring SecutirySpring Session集成使用,并想确保安全信息都传到下游机器,你就需要配置这个filter。

1.15 SecureHeaders 过滤工厂

添加一系列起安全作用的响应头。Spring Cloud Gateway参考了这篇博客的建议:https://blog.appcanary.com/2017/http-security-headers.html

默认会添加如下Header(包括值):

  • X-Xss-Protection:1; mode=block
  • Strict-Transport-Security:max-age=631138519
  • X-Frame-Options:DENY
  • X-Content-Type-Options:nosniff
  • Referrer-Policy:no-referrer
  • Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'
  • X-Download-Options:noopen
  • X-Permitted-Cross-Domain-Policies:none

如果你想修改这些Header的值,可使用如下配置:

前缀:spring.cloud.gateway.filter.secure-headers

上面的header对应的后缀:

  • xss-protection-header
  • strict-transport-security
  • frame-options
  • content-type-options
  • referrer-policy
  • content-security-policy
  • download-options
  • permitted-cross-domain-policies

例如:spring.cloud.gateway.filter.secure-headers.xss-protection-header: 你想要的值

如果想禁用某些Header,可使用如下配置:spring.cloud.gateway.filter.secure-headers.disable ,多个用 , 分隔。例如:spring.cloud.gateway.filter.secure-headers.disable=frame-options,download-options

1.16 SetPath 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: setpath_route
        uri: https://example.org
        predicates:
        - Path=/foo/{segment}
        filters:
        - SetPath=/{segment}

采用路径 template参数,通过请求路径的片段的模板化,来达到操作修改路径的母的,运行多个路径片段模板化。

如上配置,访问 ${GATEWAY_PATH}/foo/bar ,则对于后端微服务的路径会修改为 /bar

1.17 SetResponseHeader 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: setresponseheader_route
        uri: http://example.org
        filters:
        - SetResponseHeader=X-Response-Foo, Bar

如果后端服务响应带有名为 X-Response-Foo 的响应头,则将值改为替换成 Bar

1.18 SetStatus 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: setstatusstring_route
        uri: http://example.org
        filters:
        - SetStatus=BAD_REQUEST
      - id: setstatusint_route
        uri: http://example.org
        filters:
        - SetStatus=401

修改响应的状态码,值可以是数字,也可以是字符串。但一定要是Spring HttpStatus 枚举类中的值。如上配置,两种方式都可以返回HTTP状态码401。

1.19 StripPrefix 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: nameRoot
        uri: http://nameservice
        predicates:
        - Path=/name/**
        filters:
        - StripPrefix=2

数字表示要截断的路径的数量。如上配置,如果请求的路径为 /name/bar/foo ,则路径会修改为 /foo ,也就是会截断2个路径。

1.20 Retry 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: retry_test
        uri: http://localhost:8080/flakey
        predicates:
        - Host=*.retry.com
        filters:
        - name: Retry
          args:
            retries: 3
            statuses: BAD_GATEWAY

针对不同的响应做重试,可配置如下参数:

  • retries: 重试次数
  • statuses: 需要重试的状态码,取值在 org.springframework.http.HttpStatus
  • methods: 需要重试的请求方法,取值在 org.springframework.http.HttpMethod
  • series: HTTP状态码系列,取值在 org.springframework.http.HttpStatus.Series

1.21 RequestSize 过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: request_size_route
      uri: http://localhost:8080/upload
      predicates:
      - Path=/upload
      filters:
      - name: RequestSize
        args:
          # 单位字节
          maxSize: 5000000

为后端服务设置收到的最大请求包大小。如果请求大小超过设置的值,则返回 413 Payload Too Large 。默认值是5M

1.22 默认过滤器工厂

spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Foo, Default-Bar
      - PrefixPath=/httpbin

2、AddRequestHeader 过滤工厂

【微服务架构】SpringCloud Alibaba(六):SpringCloud Gateway网关(过滤器工厂配置)_第1张图片

  • 断点打在 org.springframework.cloud.gateway.filter.NettyRoutingFilter#filter ,就可以调试Gateway转发的具体细节了

  • 添加如下配置,可观察到一些请求细节:

    logging:
      level:
        org.springframework.cloud.gateway: trace
        org.springframework.http.server.reactive: debug
        org.springframework.web.reactive: debug
        reactor.ipc.netty: debug
    

    【微服务架构】SpringCloud Alibaba(六):SpringCloud Gateway网关(过滤器工厂配置)_第2张图片

3、自定义过滤器

3.1 过滤器生命周期

  • pre : Gateway转发请求之前
  • post : Gateway转发请求之后

3.2 自定义过滤器工厂的方式

  • 自定义过滤器工厂-方式1

    继承: AbstractGatewayFilterFactory

    参考示例:org.springframework.cloud.gateway.filter.factory.RequestSizeGatewayFilterFactory

    spring:
      cloud:
        gateway:
          routes:
          filters:
          - name: RequestSize
            args:
              # 单位字节
              maxSize: 5000000
    
  • 自定义过滤器工厂-方式2

    继承: AbstractNaeValueGatewayFilterFactory 【AbstractNaeValueGatewayFilterFactory 其实继承了AbstractGatewayFilterFactory,所以AbstractNaeValueGatewayFilterFactory 对AbstractGatewayFilterFactory的简化】

    参考示例:org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory

    spring:
      cloud:
        gateway:
          routes:
          - id: add_response_header_route
            uri: https://example.org
            filters:
            - AddResponseHeader=X-Response-Foo, Bar
    

3.3 核心API

  • exchange.getRequest().mutate().xxx//修改request
  • exchange.mutate().xxx//修改exchange
  • chain.filter(exchange)//传递给下一个过滤器处理
  • exchange.getResponse()//拿到响应
// 这里的过滤器和我们以前的过滤器还不一样,tomcat过滤器是属于HttpServletRequst\HttpServletResponse
// 我们这里底层是基于Netty的,它是将我们的请求和响应封装到我们的ServerWebExchange然后进行出里这里是对应的变化

【微服务架构】SpringCloud Alibaba(六):SpringCloud Gateway网关(过滤器工厂配置)_第3张图片

3.4 编写一个过滤器工厂

记录日志

  • 编写的类一定以GatewayFilterFactory结尾

  • 代码

    
    @Slf4j
    @Component
    public class PrintLogGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
        @Override
        public GatewayFilter apply(NameValueConfig config) {
            // 放到这里应用启动的时候会执行两次次,这是一个坑,需要放到方法里面
          //   log.info("打印请求信息:{}:{}",config.getName(),config.getValue());
            return new GatewayFilter() {
    
                @Override
                public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                    log.info("打印请求信息:{}:{}",config.getName(),config.getValue());
                    // 获取request就可以进行修改了
                    ServerHttpRequest modifiedRequest = exchange.getRequest().mutate().build();
                    // 设置请求值
    //                ServerHttpRequest modifiedRequest = exchange.getRequest().mutate()
    //                        .header(config.getName(), value).build();
                    ServerWebExchange modifiedExchange = exchange.mutate().request(modifiedRequest).build();
                    return chain.filter(modifiedExchange);
                }
            };
        }
    }
    
  • 配置

    【微服务架构】SpringCloud Alibaba(六):SpringCloud Gateway网关(过滤器工厂配置)_第4张图片

4、全局过滤器

前面的 GatewayFilter 工厂是在某一特定路由策略中设置的,仅对这一种路由生效。若要使某些过滤效果应用到所有路由策略中,就可以将该 GatewayFilter 工厂定义在全局Filters中。修改 gateway 工程配置文件。

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#global-filters

【微服务架构】SpringCloud Alibaba(六):SpringCloud Gateway网关(过滤器工厂配置)_第5张图片

GlobalFilter 接口和 GatewayFilter 有一样的接口定义,只不过, GlobalFilter 会作用于所有路由。

官方声明:GlobalFilter的接口定义以及用法在未来的版本可能会发生变化。

4.1 LoadBalancerClientFilter

LoadBalancerClientFilter 会查看exchange的属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的 值(一个URI),如果该值的scheme是 lb,比如:lb://dyll-user,它将会使用Spring Cloud的LoadBalancerClient 来 将 dyll-user解析成实际的host和port,并替换掉 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的内 容。

其实就是用来整合负载均衡器Ribbon的

【微服务架构】SpringCloud Alibaba(六):SpringCloud Gateway网关(过滤器工厂配置)_第6张图片

【微服务架构】SpringCloud Alibaba(六):SpringCloud Gateway网关(过滤器工厂配置)_第7张图片

4.2 自定义过滤器

  1. 实现GlobalFilter接口

  2. 增加Order注解,值越小越靠前

  3. @Component

    @Slf4j
    @Component
    public class IPAddressStatisticsFilter implements GlobalFilter, Ordered {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            InetSocketAddress host = exchange.getRequest().getHeaders().getHost();
            if (host == null || host.getHostName() == null) {
                exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
                return exchange.getResponse().setComplete();
            }
            String hostName = host.getHostName();
            AtomicInteger count = IpCache.CACHE.getOrDefault(hostName, new AtomicInteger(0));
            count.incrementAndGet();
            IpCache.CACHE.put(hostName, count);
            log.info("IP地址:" + hostName + ",访问次数:" + count.intValue());
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return -1;
        }
    }
    
    public class IpCache {
        public static final Map<String, AtomicInteger> CACHE = new ConcurrentHashMap<>();
    }
    

你可能感兴趣的:(#,架构师进阶-微服务架构,架构,微服务,spring,cloud)