8、gateway使用和原理

一、什么是Spring Cloud Gateway

1、网关简介

网关作为流量的入口,常用的功能包括路由转发,权限校验,限流等。

2、Gateway简介

Spring Cloud Gateway 是Spring Cloud官方推出的第二代网关框架,定位于取代 Netflix Zuul。相比 Zuul 来说,Spring Cloud Gateway 提供更优秀的性能,更强大的有功能。

Spring Cloud Gateway 是由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。

它不能在传统的 servlet 容器中工作,也不能构建成 war 包。

Spring Cloud Gateway 旨在为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的基本功能,例如说安全认证、监控、限流等等。

网文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-starter

3、核心概念

  • 路由(route)

    路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组谓 词工厂、一组Filter组成。如果谓词为真,则说明请求的URL和配置的路由匹配。

  • 谓词(predicates)

    即java.util.function.Predicate , Spring Cloud Gateway使用Predicate实现路由的匹配条件。

  • 过滤器(Filter)

    SpringCloud Gateway中 的filter分为Gateway FilIer和Global Filter。Filter可以对请求和响应进行处理。

    【路由就是转发规则,谓词就是是否走这个路径的条件,过滤器可以为路由添加业务逻辑,修改请求以及响应】

示例演示

spring:cloud:gateway:routes:#路由ID全局唯一- id: msb-order-route#目标微服务的请求地址和端口uri: http://localhost:8001predicates:- Path=/order/*filters:- AddRequestHeader=X-Request-Foo, Bar

这里就演示了请求 /order/*的路径就会路由到上边这个url上去

2、 工作原理

Spring Cloud Gateway 的工作原理跟 Zuul 的差不多,最大的区别就是 Gateway 的 Filter 只有 pre 和 post 两种。

Spring Cloud Gateway Diagram

客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关 Web 处理程序,此时处理程序运行特定的请求过滤器链。

过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre 过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行 post 过滤器逻辑。

4、快速入门

3.1环境搭建

引入依赖

  <!--  gateway网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency></dependencies><!--  nacos注册中心--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>

父工程的pom

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
</dependencies>
spring:application:name: msb-gatewaycloud:nacos:discovery:server-addr: localhost:8848gateway:discovery:locator:#默认值是false,如果设为true开启通过微服务创建路由的功能,即可以通过微服务名访问服务#http://localhost:13001/msb-order/order/create#不建议打开,因为这样暴露了服务名称enabled: true#是否开启网关enabled: true

这里注意不要引入springmvc工程否则会报错如下:

image.png

我们工程中如下:

msb-gateway工程的pom

<dependencies><!--  gateway网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><scope>test</scope> <!-- 特殊处理,不引入父工程依赖 --></dependency>
</dependencies>

3.2 测试

image.png

我们刚才说了我们不建议开启通过微服务创建路由的功能,这样就把微服务名称暴露了,如果设置位默认值在请求一下,是否能成功呢? 我们测试一下:

image.png

是失败的,刚才能成功主要是

http://localhost:13001/msb-order/order/create 可以进行转化:

http://localhost:13001/msb-order/order/create可以替换为http://localhost:8001/order/create

然而此时的请求是转化不了的

http://localhost:13001/order/create

这是我们就需要我们的gateway 中的 route& predicates 建立映射

二、路由谓词工厂(Route Predicate Factories)配置

1、路由配置的两种形式

1.1 路由到指定URL

  • 通配

    spring:cloud:gateway:routes:- id: {唯一标识}uri: http://localhost:8001
    

    表示访问 GATEWAY_URL/** 会转发到 http://localhost:8001/**

    注:上面路由的配置必须和下面谓词(Predicate)配合使用才行

  • 精确匹配

    spring:cloud:gateway:routes:- id: {唯一标识}uri: http://localhost:8001/predicates:- Path=/order/*
    

    表示访问 GATEWAY_URL/order/*会转发到 http://localhost:8001/order/*

1.2 路由到服务发现组件上的微服务

  • 通配

    spring:cloud:gateway:routes:- id: {唯一标识}uri: lb://msb-order
    

    表示访问 GATEWAY_URL/** 会转发到 msb-order 微服务的 /**

    注:上面路由的配置必须和下面谓词(Predicate)配合使用才行

  • 精确匹配

    spring:cloud:gateway:routes:- id: {唯一标识}uri: lb://msb-order/predicates:- Path=/order/*
    

    表示访问 GATEWAY_URL/order/ 会转发到 msb-order 微服务的 /order/

2、谓词工厂分类

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

网关启动日志:

image.png

image.png

3、谓词介绍

3.1 After路由断言工厂

规则:

该断言工厂的参数是一个 UTC 格式的时间。其会将请求访问到 Gateway 的时间与该参数时间相比,若请求时间在参数时间之后,则匹配成功,断言为 true。

配置:

spring:cloud:gateway:routes:- id: after_routeuri: lb://msb-userpredicates:# 当且仅当请求时的时间After配置的时间时,才会转发到用户微服务# 目前配置不会进该路由配置,所以返回404# 将时间改成 < now的时间,则访问localhost:8040/** -> msb-user/**# eg. 访问http://localhost:8040/users/1 -> msb-user/users/1- After=2030-01-20T17:42:47.789-07:00[America/Denver]

技巧:时间可使用 System.out.println(ZonedDateTime.now()); 打印,然后即可看到时区。例如:2019-08-10T16:50:42.579+08:00[Asia/Shanghai]

时间格式的相关逻辑:

  • 默认时间格式:org.springframework.format.support.DefaultFormattingConversionService#addDefaultFormatters
  • 时间格式注册:org.springframework.format.datetime.standard.DateTimeFormatterRegistrar#registerFormatters

3.2 Before路由断言工厂

规则:

该断言工厂的参数是一个 UTC 格式的时间。其会将请求访问到 Gateway 的时间与该参数时间相比,若请求时间在参数时间之前,则匹配成功,断言为 true。

配置:

spring:cloud:gateway:routes:- id: before_routeuri: lb://msb-userpredicates:# 当且仅当请求时的时间Before配置的时间时,才会转发到用户微服务# 目前配置不会进该路由配置,所以返回404# 将时间改成 > now的时间,则访问localhost:8040/** -> msb-user/**# eg. 访问http://localhost:8040/users/1 -> msb-user/users/1- Before=2018-01-20T17:42:47.789-07:00[America/Denver]

3.3 Between路由断言工厂

规则:

该断言工厂的参数是两个 UTC 格式的时间。其会将请求访问到 Gateway 的时间与这两个参数时间相比,若请求时间在这两个参数时间之间,则匹配成功,断言为 true。

配置:

spring:cloud:gateway:routes:- id: between_routeuri: lb://msb-userpredicates:# 当且仅当请求时的时间Between配置的时间时,才会转发到用户微服务# 因此,访问localhost:8040/** -> msb-user/**# eg. 访问http://localhost:8040/users/1 -> msb-user/users/1- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2027-01-21T17:42:47.789-07:00[America/Denver]

3.4 Cookie路由断言工厂

规则:

该断言工厂中包含两个参数,分别是 cookie 的 key 与 value。当请求中携带了指定 key与 value 的 cookie 时,匹配成功,断言为 true。

配置:

spring:cloud:gateway:routes:- id: cookie_routeuri: lb://msb-userpredicates:# 当且仅当带有名为somecookie,并且值符合正则ch.p的Cookie时,才会转发到用户微服务# 如Cookie满足条件,则访问http://localhost:8040/** -> msb-user/**# eg. 访问http://localhost:8040/users/1 -> msb-user/users/1- Cookie=somecookie, ch.p

3.5 Header路由断言工厂

规则:

该断言工厂中包含两个参数,分别是请求头 header 的 key 与 value。当请求中携带了指定 key 与 value 的 header 时,匹配成功,断言为 true。

配置:

spring:cloud:gateway:routes:- id: header_routeuri: lb://msb-userpredicates:# 当且仅当带有名为X-Request-Id,并且值符合正则\d+的Header时,才会转发到用户微服务# 如Header满足条件,则访问http://localhost:8040/** -> msb-user/**# eg. 访问http://localhost:8040/users/1 -> msb-user/users/1- Header=X-Request-Id, \d+

3.6 Host路由断言工厂

规则:

该断言工厂中包含的参数是请求头中的 Host 属性。当请求中携带了指定的 Host 属性值时,匹配成功,断言为 true。

配置:

spring:cloud:gateway:routes:- id: host_routeuri: lb://user-centerpredicates:# 当且仅当名为Host的Header符合**.somehost.org或**.anotherhost.org时,才会转发用户微服务# 如Host满足条件,则访问http://localhost:8040/** -> user-center/**# eg. 访问http://localhost:8040/users/1 -> user-center/users/1- Host=**.somehost.org,**.anotherhost.org

3.7 Method路由断言工厂

规则:

该断言工厂用于判断请求是否使用了指定的请求方法,是 POST,还是 GET 等。当请求中使用了指定的请求方法时,匹配成功,断言为 true。

配置:

spring:cloud:gateway:routes:- id: method_routeuri: lb://msb-userpredicates:# 当且仅当HTTP请求方法是GET时,才会转发用户微服务# 如请求方法满足条件,访问http://localhost:8040/** -> msb-user/**# eg. 访问http://localhost:8040/users/1 -> msb-user/users/1- Method=GET

3.8 Path路由断言工厂

规则:

该断言工厂用于判断请求路径中是否包含指定的uri。若包含,则匹配成功,断言为true,此时会将该匹配上的 uri 拼接到要转向的目标 uri 的后面,形成一个统一的 uri。

配置:

spring:cloud:gateway:routes:- id: path_routeuri: lb://msb-userpredicates:# 当且仅当访问路径是/users/*或者/some-path/**,才会转发用户微服务# segment是一个特殊的占位符,单层路径匹配# eg. 访问http://localhost:8040/users/1 -> msb-user/users/1- Path=/users/{segment},/some-path/**

3.9 Query路由断言工厂

规则:

该断言工厂用于从请求中查找指定的请求参数。其可以只查看参数名称,也可以同时查看参数名与参数值。当请求中包含了指定的参数名,或名值对时,匹配成功,断言为 true。

参数:

param 请求参数的key值
regexp 请求参数的值,配置的值是 Java中的 正则表达式形式。

配置:

示例1:

spring:cloud:gateway:routes:- id: query_routeuri: lb://msb-userpredicates:# 当且仅当请求带有baz的参数,才会转发到用户微服务# eg. 访问http://localhost:8040/users/1?baz=xx -> msb-user的/users/1- Query=baz

示例2:

spring:cloud:gateway:routes:- id: query_routeuri: lb://msb-userpredicates:# 当且仅当请求带有名为foo的参数,且参数值符合正则ba.,才会转发到用户微服务# eg. 访问http://localhost:8040/users/1?baz=baz -> msb-user的/users/1?baz=baz- Query=foo, ba.

3.10 RemoteAddr路由断言工厂

规则:

该断言工厂用于判断请求提交的所要访问的 IP 地址是否在断言中指定的 IP 范围。当请求中的 IP 在指定范围时,匹配成功,断言为 true。

配置:

spring:cloud:gateway:routes:- id: remoteaddr_routeuri: lb://msb-userpredicates:# 当且仅当请求IP是192.168.1.1/24网段,例如192.168.1.10,才会转发到用户微服务# eg. 访问http://localhost:8040/users/1 -> msb-user的/users/1- RemoteAddr=192.168.1.1/24

如果我们的 Spring Cloud Gateway是位于代理后面,那么获取到 远程地址可能不正确,此时我们可以自己编写一个 RemoteAddressResolver来解决。

3.11 Weight路由断言工厂

规则:

该断言工厂中包含两个参数,分别是用于表示组 group,与权重 weight。对于同一组中的多个 uri 地址,路由器会根据设置的权重,按比例将请求转发给相应的 uri。实现负载均衡。

配置:

spring:cloud:gateway:routes:- id: weight_highuri: https://weighthigh.orgpredicates:- Weight=group1, 8- id: weight_lowuri: https://weightlow.orgpredicates:- Weight=group1, 2

group 组,权重根据组来计算
weight 权重值,是一个 Int 的值

3.12 XForwarded Remote Addr路由断言工厂

规则:

这可用于反向代理,如负载平衡器或web应用程序防火墙,其中只有当请求来自这些反向代理使用的IP地址的受信任列表时,才应允许该请求。

配置:

spring:cloud:gateway:routes:- id: xforwarded_remoteaddr_routeuri: https://example.orgpredicates:- XForwardedRemoteAddr=192.168.1.1/24

4、谓词使用

4.1 between

例如:在某个时间段下单我们送5元红包

spring:cloud:gateway:routes:#路由ID全局唯一- id: create_order#目标微服务的请求地址和端口uri: http://localhost:8001predicates:#请求某个接口在这个时间段是有效的- Between=2022-01-30T11:59:59+08:00[Asia/Shanghai], 2022-02-01T11:59:59+08:00[Asia/Shanghai]

获取某个时区的指定时间

public class TestTime {public static void main(String[] args) {// 获取某个时区当前时间ZonedDateTime zonedDateTime= ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));// 获取指定时区开始时间ZonedDateTime startTime = ZonedDateTime.of(2022, 1, 30,11, 59, 59, 0, ZoneId.of("Asia/Shanghai"));// 获取指定时区结束时间ZonedDateTime endTime = ZonedDateTime.of(2022, 2, 1,11, 59, 59, 0, ZoneId.of("Asia/Shanghai"));System.out.println("获取指定时区当前时间:" +zonedDateTime);System.out.println("获取指定时区开始时间:"+ startTime);System.out.println("获取指定时区结束时间:" + endTime);}}

4.2 Cookie匹配

spring:cloud:gateway:routes:- id: cookie_routeuri: lb://msb-userpredicates:#Cookie配置- Cookie=username, msb

image.png

4.3 head匹配

spring:cloud:gateway:routes:- id: header_routeuri: lb://msb-userpredicates:# 当且仅当带有名为X-Request-Id,并且值符合正则\d+(单个或者多个数字)的Header时,才会转发到用户微服务# 如Header满足条件,则访问http://localhost:8040/** -> msb-user/**# eg. 访问http://localhost:8040/users/1 -> msb-user/users/1- Header=X-Request-Id, \d+

image.png

4.4 Weight路由断言工厂

我们可以将配置放到nacos配置中心,使用这个路由谓词实现灰度发布
spring:cloud:gateway:routes:- id: weight_highuri: http://localhost:8081predicates:- Weight=group1, 8- Path=/order/**- id: weight_lowuri: http://localhost:8082predicates:- Weight=group1, 2- Path=/order/**

5、自定义谓词

比如我们有这样一个需求:

  • 限制08:00 - 23:00 才能访问

我们自定义一下配置:假设这个配置是这样配置的 - TimeBetween= 08:00,23:00

image.png

自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写 apply 方法的逻辑。在 apply 方法中可以通过 exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。

<font color=“red”>注意: 命名需要以 RoutePredicateFactory 结尾</font>

@Component
public class TimeBetweenRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeBetweenConfig> {public TimeBetweenRoutePredicateFactory() {super(TimeBetweenConfig.class);}@Overridepublic Predicate<ServerWebExchange> apply(TimeBetweenConfig config) {LocalTime start = config.getStart();LocalTime end = config.getEnd();return new Predicate<ServerWebExchange>() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {LocalTime now = LocalTime.now();return now.isAfter(start) && now.isBefore(end);}};}@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("start","end");}
}
  1. 继承

    AbstractRoutePredicateFactory<>
    

    需要用到泛型,这里的泛型是需要定义一个配置类来给配置参数,下面是配置类,配置开始时间和结束时间

    @Data
    public class TimeBetweenConfig {private LocalTime start;private LocalTime end;
    }
    
  2. 重写方法

     public List<String> shortcutFieldOrder() {return Arrays.asList("start","end");}
    

    用来映射参数,asList(“配置文件的第1个参数”,“配置文件的第2个参数”,“配置文件的第3个参数”,“配置文件的第4个参数”…),接给配置类,配置类得到参数后里面的参数有值然后在重写的

      public Predicate<ServerWebExchange> apply(TimeBetweenConfig config) {LocalTime start = config.getStart();LocalTime end = config.getEnd();return new Predicate<ServerWebExchange>() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {LocalTime now = LocalTime.now();return now.isAfter(start) && now.isBefore(end);}}
    

    中进行谓词配置,实现自定义谓词工厂

  3. 利用JDK8特性查看时间格式

     public static void main(String[] args) {DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);System.out.println(dateTimeFormatter.format(LocalTime.now()));}
    

三、过滤器工厂( 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_routeuri: https://example.orgfilters:- AddRequestHeader=X-Request-Foo, Bar

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

1.2 AddRequestParameter 过滤工厂

spring:cloud:gateway:routes:- id: add_request_parameter_routeuri: https://example.orgfilters:- AddRequestParameter=foo, bar

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

1.3 AddResponseHeader 过滤工厂

spring:cloud:gateway:routes:- id: add_response_header_routeuri: https://example.orgfilters:- 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_routeuri: https://example.orgfilters:- 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.msbedu.com, https://www.msbedu.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_routeuri: https://example.orgfilters:- PrefixPath=/mypath

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

1.6 PreserveHostHeader 过滤工厂

spring:cloud:gateway:routes:- id: preserve_host_routeuri: https://example.orgfilters:- PreserveHostHeader

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

1.7 RequestRateLimiter 过滤工厂

spring:cloud:gateway:routes:- id: requestratelimiter_routeuri: https://example.orgfilters:- name: RequestRateLimiterargs:redis-rate-limiter.replenishRate: 10redis-rate-limiter.burstCapacity: 20

1.8 RedirectTo 过滤工厂

spring:cloud:gateway:routes:- id: prefixpath_routeuri: https://example.orgfilters:# 配置成HTTP状态码, URL的形式- RedirectTo=302, http://www.msb.com
  • HTTP状态码应该是HTTP状态码300序列,例如301
  • URL必须是合法的URL,并且该值会作为名为 Location 的Header。

上面配置表达的意思是: ${GATEWAY_URL}/hello 会重定向到 https://ecme.org/hello ,并且携带一个 Location:http://www.msb.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_routeuri: https://example.orgfilters:- RemoveRequestHeader=X-Request-Foo

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

1.11 RemoveResponseHeader 过滤工厂

spring:cloud:gateway:routes:- id: removeresponseheader_routeuri: https://example.orgfilters:- RemoveResponseHeader=X-Response-Foo

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

1.12 RewritePath 过滤工厂

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

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

1.13 RewriteResponseHeader 过滤工厂

spring:cloud:gateway:routes:- id: rewriteresponseheader_routeuri: https://example.orgfilters:- 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_sessionuri: https://example.orgpredicates:- 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_routeuri: https://example.orgpredicates:- Path=/foo/{segment}filters:- SetPath=/{segment}

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

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

1.17 SetResponseHeader 过滤工厂

spring:cloud:gateway:routes:- id: setresponseheader_routeuri: http://example.orgfilters:- SetResponseHeader=X-Response-Foo, Bar

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

1.18 SetStatus 过滤工厂

spring:cloud:gateway:routes:- id: setstatusstring_routeuri: http://example.orgfilters:- SetStatus=BAD_REQUEST- id: setstatusint_routeuri: http://example.orgfilters:- SetStatus=401

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

1.19 StripPrefix 过滤工厂

spring:cloud:gateway:routes:- id: nameRooturi: http://nameservicepredicates:- Path=/name/**filters:- StripPrefix=2

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

1.20 Retry 过滤工厂

spring:cloud:gateway:routes:- id: retry_testuri: http://localhost:8080/flakeypredicates:- Host=*.retry.comfilters:- name: Retryargs:retries: 3statuses: 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_routeuri: http://localhost:8080/uploadpredicates:- Path=/uploadfilters:- name: RequestSizeargs:# 单位字节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 过滤工厂

image.png

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

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

    logging:level:org.springframework.cloud.gateway: traceorg.springframework.http.server.reactive: debugorg.springframework.web.reactive: debugreactor.ipc.netty: debug
    

    image.png

3、自定义过滤器

3.1 过滤器生命周期

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

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

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

    继承: AbstractGatewayFilterFactory

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

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

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

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

    spring:cloud:gateway:routes:- id: add_response_header_routeuri: https://example.orgfilters:- 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然后进行出里这里是对应的变化

image.png

3.4 编写一个过滤器工厂

记录日志

  • 编写的类一定以GatewayFilterFactory结尾

  • 代码

    
    @Slf4j
    @Component
    public class PrintLogGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {// 放到这里应用启动的时候会执行两次次,这是一个坑,需要放到方法里面//   log.info("打印请求信息:{}:{}",config.getName(),config.getValue());return new GatewayFilter() {@Overridepublic 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);}};}
    }
    
  • 配置

    image.png

4、全局过滤器

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

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

image.png

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

<font color=“red”>官方声明:GlobalFilter的接口定义以及用法在未来的版本可能会发生变化。 </font>

4.1 LoadBalancerClientFilter

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

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

image.png

image.png

4.2 自定义过滤器

  1. 实现GlobalFilter接口

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

  3. @Component

    @Slf4j
    @Component
    public class IPAddressStatisticsFilter implements GlobalFilter, Ordered {@Overridepublic 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);}@Overridepublic int getOrder() {return -1;}
    }
    
    public class IpCache {public static final Map<String, AtomicInteger> CACHE = new ConcurrentHashMap<>();
    }
    

四、源码分析

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/5319.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

省电液晶驱动IC,VK2C22G,COG片高抗干扰抗噪系列LCD段码驱动芯片,I2C通信接口

型号:VK2C22G DICE(邦定COB)/COG&#xff08;绑定玻璃用&#xff09; VK2C22G概述&#xff1a; VK2C22G是一个点阵式存储映射的LCD驱动器&#xff0c;可支持最大176点&#xff08;44SEGx4COM&#xff09;的LCD屏。单片机可通过I2C接口配置显示参数和读写显示数据&#…

计算机网络 day7 扫描IP脚本 - 路由器 - ping某网址的过程

目录 network 和 NetworkManager关系&#xff1a; 实验&#xff1a;编写一个扫描脚本&#xff0c;知道本局域网里哪些ip在使用&#xff0c;哪些没有使用&#xff1f; 使用的ip对应的mac地址都要显示出来 计算机程序执行的两种不同方式&#xff1a; shell语言编写扫描脚本 …

C# 通过枚举类型字符串,反射到枚举上

C# 通过枚举类型字符串&#xff0c;反射到枚举上 通过类型字符串&#xff0c;反射出任意类型枚举类型通过反射调用枚举GetTypeByName(EnumName) 为空&#xff1f; 小结 通过类型字符串&#xff0c;反射出任意类型 之前老顾写过一篇博客&#xff0c;通过反射&#xff0c;使用字…

IDEA+java+spring+hibernate+jquery+mysql后台管理系统

IDEA javaspringhibernatejquerymysql后台管理系统 一、系统介绍1.环境配置 二、系统展示1. 管理员登录2.修改密码3.我的内容4.我的操作日志5. 我的登陆日志6. 我的登陆授权7. 内容管理8.标签管理9. 搜索词管理10.分类管理11.分类类型12.标签分类13.用户管理14.部门管理15.角色…

Linux系统编程(信号处理机制)

文章目录 前言一、中断&#xff0c;异常&#xff0c;信号的区别二、信号在Linux中的标识三、信号处理相关函数四、代码实验总结 前言 本篇文章我们来讲解信号的处理机制&#xff0c;信号处理在Linux操作系统中必不可少&#xff0c;这一点值得大家注意&#xff0c;信号又会与中…

golang 日志库zap和日志切割实践

介绍 在许多Go语言项目中&#xff0c;我们需要一个好的日志记录器能够提供下面这些功能&#xff1a; 能够将事件记录到文件中&#xff0c;而不是应用程序控制台。 日志切割-能够根据文件大小、时间或间隔等来切割日志文件。 支持不同的日志级别。例如INFO&#xff0c;DEBUG&a…

深度学习与神经网络

人工智能&#xff0c;机器学习&#xff0c;深度学习&#xff0c;神经网络&#xff0c;emmmm&#xff0c;傻傻分不清楚&#xff0c;这都啥呀&#xff0c;你知道吗&#xff1f;我不知道。你知道吗&#xff1f;我不知道。 来来来&#xff0c;接下来&#xff0c;整硬菜&#xff1a…

『红外图像 数据增强』DDE(Digital Detail Enhancement)算法

DDE处理的细节 分离背景层和细节层&#xff1a;使用特殊的滤波器&#xff0c;将图像分成背景层和细节层。背景层通常包含低频信息&#xff0c;而细节层包含高频信息。 对背景层进行灰度增强&#xff1a;通过对背景层应用适当的灰度增强算法&#xff0c;提高背景层的对比度和视…

轻量级应用服务器开放端口

关于使用浏览器连接自己所写的TCP进程时&#xff0c;由于没有开放端口&#xff0c;而且搜索到对应的操作来进行开放端口&#xff0c;所以在完成开放端口后特意做个笔记&#xff0c;防止忘记。 登录自己所使用的服务器的网站找到控制台 找到轻量级应用服务器 找到所需要开放端口…

【机器学习】分类算法 - KNN算法(K-近邻算法)KNeighborsClassifier

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;零基础快速入门人工智能《机器学习入门到精通》 K-近邻算法 1、什么是K-近邻算法&#xff1f;2、K-近邻算法API3、…

最强自动化框架,Pytest自动化测试-动态切换环境实战(超细整理)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 在开始前&#xf…

LangChain大型语言模型(LLM)应用开发(五):评估

LangChain是一个基于大语言模型&#xff08;如ChatGPT&#xff09;用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口&#xff0c;可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互&#x…

ceph应用

资源池 Pool 管理 上面我们已经完成了 Ceph 集群的部署&#xff0c;但是我们如何向 Ceph 中存储数据呢&#xff1f;首先我们需要在 Ceph 中定义一个 Pool 资源池。Pool 是 Ceph 中存储 Object 对象抽象概念。我们可以将其理解为 Ceph 存储上划分的逻辑分区&#xff0c;Pool 由多…

Qt6 Qt Quick UI Prototype学习QML第一篇

Qt6 Qt Quick UI原型学习QML第一篇 开始创建项目Qt Quick UI原型简介.qmlproject文件举例Window平台小例子运行效果QML语法 了解语法 开始创建项目 创建一个具有QML入口点的Qt Quick 2 UI项目。要使用它&#xff0c;您需要设置一个QML运行时环境&#xff0c;例如gmlscene。 仅当…

消息队列——rabbitmq的不同工作模式

目录 Work queues 工作队列模式 Pub/Sub 订阅模式 Routing路由模式 Topics通配符模式 工作模式总结 Work queues 工作队列模式 C1和C2属于竞争关系&#xff0c;一个消息只有一个消费者可以取到。 代码部分只需要用两个消费者进程监听同一个队里即可。 两个消费者呈现竞争关…

安全防御 --- DDOS攻击(01)

DOS攻击&#xff08;deny of service&#xff09;--- 拒绝式服务攻击 例&#xff1a;2016年10月21日&#xff0c;美国提供动态DNS服务的DynDNS遭到DDOS攻击&#xff0c;攻击导致许多使用DynDNS服务的网站遭遇访问问题&#xff0c;此事件中&#xff0c;黑客人就是运用了DNS洪水…

golang waitgroup

案例 WaitGroup 可以解决一个 goroutine 等待多个 goroutine 同时结束的场景&#xff0c;这个比较常见的场景就是例如 后端 worker 启动了多个消费者干活&#xff0c;还有爬虫并发爬取数据&#xff0c;多线程下载等等。 我们这里模拟一个 worker 的例子 package mainimport (…

ChatGPT与Claude对比分析

一 简介 1、ChatGPT: 访问地址&#xff1a;https://chat.openai.com/ 由OpenAI研发,2022年11月发布。基于 transformer 结构的大规模语言模型,包含1750亿参数。训练数据集主要是网页文本,聚焦于流畅的对话交互。对话风格友好,回复通顺灵活,富有创造性。存在一定的安全性问题,可…

【深度学习】基于BRET的高级主题检测

一、说明 使用BERT,UMAP和HDBSCAN捕获文档主题,紧随最先进的BERTopic架构(transformer编码器)。 主题检测是一项 NLP 任务,旨在从文本文档语料库中提取全局“主题”。例如,如果正在查看书籍描述的数据集,主题检测将使我们能够将书籍分类,例如:“浪漫”、“科幻”、“旅…

Springboot+Flask+Neo4j+Vue2+Vuex+Uniapp+Mybatis+Echarts+Swagger综合项目学习笔记

文章目录 Neo4j教程&#xff1a;Neo4j高性能图数据库从入门到实战 医疗问答系统算法教程&#xff1a;医学知识图谱问答系统项目示例&#xff1a;neo4j知识图谱 Vueflask 中药中医方剂大数据可视化系统可视化技术&#xff1a;ECharts、D.jsflask教程&#xff1a;速成教程Flask w…