SpringCloud之Gateway

Spring Cloud Gateway

最近在看项目中的SpringCloud的网关Gateway的代码,发现里面的过滤器以及各种网关代理写法,有点无法下手,便打算从官网方面找些资料来加深了解,之前是有写过demo,但是理解不算深!

一、网关的概念

Spring Cloud GateWay它是提供了一个建立在Spring生态系统之上的API网关,包括:Spring 5、Spring Boot 2和project Reactor。
旨在提供一种简单而有效的方法来路由到api,并为它们提供跨领域的关注点,例如:安全性、监控/度量和弹性。
在这里插入图片描述
在这里插入图片描述

二、Route

简介

路由,网关的基本组成模块,它由ID、目标代理的URI、断言集合和过滤器集合所组成,可以先看一下大致的结构:

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates: #对以下断言集合属性做控制
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue
        - Path=/api/pvs/** #此等路径将视为provider应用
        filters:
        	- StripPrefix=1 #截取掉/api,实际-Path就为 /pvs/【注意:这是网关配置了context-pah的情况下才需要,否则不需要配置】
            # 限流过滤器,使用gateway内置令牌算法
            - name: RequestRateLimiter
              args:
                # 令牌桶每秒填充平均速率,即行等价于允许用户每秒处理多少个请求平均数
                redis-rate-limiter.replenishRate: 10
                # 令牌桶的容量,允许在一秒钟内完成的最大请求数
                redis-rate-limiter.burstCapacity: 20
                # 用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。
                key-resolver: "#{@apiKeyResolver}"

注意:predicates和filters在yaml中写法有2种,上述是官网推荐的一种写法,可以在源码中找到,后面我再继续说一下,gateway网关,初始化的过程,是什么样子,就会知道为什么会有标准方法这一说了,标准是可以在源码中找到对应的痕迹的。

Route Predicate Factories

路由断言工厂类,SpringCloudGateway将路由作为SpringWebFlux HandlerMapping基础设施的一部分进行匹配。SpringCloudGateway包含许多内置的路由断言工厂,所有的这些断言都是为了组合出我们预期的http请求类型,可以根据需要进行组装各类断言来应对。

The After Route Predicate Factory

after路由断言工厂接受一个参数datetime(这是一个javazonedatetime)。此谓词匹配在指定日期时间之后发生的请求。以下示例配置after route谓词:

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]

断言适配:2017年1月20日17:42以后的所有http请求【美国-丹佛】

The Before Route Predicate Factory

before路由断言工厂接受一个参数datetime(这是一个javazonedatetime)。此谓词匹配在指定日期时间之前发生的请求。以下示例配置after route谓词:

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: https://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

断言适配:2017年1月20日17:47之前的所有http请求【美国-丹佛】

The Between Route Predicate Factory

between 路由时间段请求断言工厂

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]

【断言适配】:时间段内的http请求

The Header Route Predicate Factory

head头部断言,是由两个参数组成【header,regexp】

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

The Host Route Predicate Factory

host请求ip主机地址断言,只有一个patterns,是一个集合,包含多个正则表达式。源码【HostRoutePredicateFactory】

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

The Method Route Predicate Factory

方法断言工厂,由一个参数【method】组成,值为对应的java类枚举【HttpMethod】get、post、put、patch、delete等方法
源码【MethodRoutePredicateFactory】

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://example.org
        predicates:
        - Method=GET,POST

如果请求方法是GETPOST,则此路由匹配

The Path Route Predicate Factory

方法断言工厂,由2个参数【patterns,matchOptionalTrailingSeparator】组成,前者是一个正则数组,后缀是一个布尔类型值

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment}

The Query Route Predicate Factory

请求方法参数值断言工厂,两个【param,regexp】参数组成
两种使用方式:

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=green

请求方法含有green参数,则匹配

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=red, gree.

请求方法red参数的值符合正则表达式gree.,则匹配

The RemoteAddr Route Predicate Factory

请求的来源远程主机地址,由2个参数【sources,remoteAddressResolver】组成!

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

如果请求的远程地址是192.168.1.10,则此路由匹配。
注意:默认情况下,RemoteAddr路由断言工厂使用来自传入请求的远程地址。如果SpringCloudGateway位于代理层之后,则这可能与实际的客户端IP地址不匹配
【官网原话解决方案】

您可以通过设置自定义的RemoteAddressResolver自定义解析远程地址的方式。
SpringCloudGateway提供了一个非默认的远程地址解析程序,它基于X-Forwarded-For报头xForwardedRemoteAddResolver。
XForwardedRemoteAddressResolver有两个静态构造函数方法,它们采用不同的安全方法:
1.trustAll:
返回一个RemoteAddressResolver,它始终采用X-Forwarded-For头中找到的第一个IP地址。
此方法易受欺骗,因为恶意客户端可能为X-Forwarded-for设置初始值,解析程序将接受该值。
2.maxTrustedIndex:
获取一个索引,该索引与在Spring Cloud网关前运行的受信任基础设施的数量相关。
如果Spring Cloud Gateway仅可通过HAProxy访问,则应使用值1。
如果在访问Spring Cloud网关之前需要两跳可信基础设施,则应使用值2。
您可以通过设置自定义的RemoteAddressResolver自定义解析远程地址的方式。

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%的流量转发到weighlow.org

yaml文件predicts、filters2种写法

以Header为例,找到对应的header断言工厂,可以找到标准、缩减版的写法

/**
 * @author Spencer Gibb
 */
public class HeaderRoutePredicateFactory
		extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {
	/**
	 * Header key.
	 */
	public static final String HEADER_KEY = "header";
	/**
	 * Regexp key.
	 */
	public static final String REGEXP_KEY = "regexp";
	
	@Override
	public List<String> shortcutFieldOrder() {
		return Arrays.asList(HEADER_KEY, REGEXP_KEY);
	}
	/*省略代码*/
}

缩减版

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

标准版

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - name: Header
          args:
            header: X-Request-Id
            regexp: \d+

对于【routes】可以在找到痕迹

public class RouteDefinition {

	@NotEmpty
	private String id = UUID.randomUUID().toString();

	@NotEmpty
	@Valid
	private List<PredicateDefinition> predicates = new ArrayList<>();

	@Valid
	private List<FilterDefinition> filters = new ArrayList<>();

	@NotNull
	private URI uri;

	private int order = 0;

	public RouteDefinition() {
	}

	public RouteDefinition(String text) {
		int eqIdx = text.indexOf('=');
		if (eqIdx <= 0) {
			throw new ValidationException("Unable to parse RouteDefinition text '" + text
					+ "'" + ", must be of the form name=value");
		}

		setId(text.substring(0, eqIdx));

		String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");

		setUri(URI.create(args[0]));

		for (int i = 1; i < args.length; i++) {
			this.predicates.add(new PredicateDefinition(args[i]));
		}
	}
}

而对于【name-args】的写法,可以在下面的源码找到痕迹

public class PredicateDefinition {

	@NotNull
	private String name;

	private Map<String, String> args = new LinkedHashMap<>();

	public PredicateDefinition() {
	}

	public PredicateDefinition(String text) {
		int eqIdx = text.indexOf('=');
		if (eqIdx <= 0) {
			throw new ValidationException("Unable to parse PredicateDefinition text '"
					+ text + "'" + ", must be of the form name=value");
		}
		setName(text.substring(0, eqIdx));

		String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");

		for (int i = 0; i < args.length; i++) {
			this.args.put(NameUtils.generateName(i), args[i]);
		}
	}

三、GatewayFilter工厂簇

路由过滤器,在特定路由下,允许我们以某种方式修改传入的HTTP请求或传出的HTTP响应。SpringCloudGateway内置了很多工厂供我们根据不同情况去使用。

The AddRequestHeader GatewayFilter Factory

头部信息新增过滤器工厂,由【name,value】2个参数组成

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

将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}

使用变量占位符,也可以动态新增参数

The AddRequestParameter GatewayFilter Factory

请求参数新增过滤器工厂,由【name,value】2个参数组成

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

为所有匹配请求的下游请求的查询字符串添加参数red=blue

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

使用变量占位符,也可以动态新增参数

The AddResponseHeader GatewayFilter Factory

请求返回的头新增过滤器工厂,由2个参数【name,value】组成

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

返回的请求头部,新增上一个header属性及值
同样,也支持动态新增

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

The DedupeResponseHeader GatewayFilter Factory

删除response header中重复的数据项,2个参数【name、strategy】组成,name可以由空格分隔的一个列表组成,分别有三种数据保留策略【RETAIN_FIRST(默认)、RETAIN_LAST、RETAIN_UNIQUE】

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

这将删除访问控制允许凭据【Access-Control-Allow-Credentials】和访问控制允许源响应头【Access-Control-Allow-Origin】的重复值,以防网关CORS逻辑和下游逻辑都添加它们

The Hystrix GatewayFilter Factory

熔断器,集成了Netflix开源的Hystrix框架熔断功能,为了避免服务在故障时引发级联故障,通过Hystrix允许下游服务故障时提供熔断返回或者请求转发操作;
主要转发逻辑在RouteHystrixCommand中resumeWithFallback函数中。

spring:
  cloud:
    gateway:
      routes:
      - id: hystrix_route
        uri: https://example.org
        filters:
        - Hystrix=myCommandName

Hystrix过滤器还可以接受可选的fallbackUri参数。目前,只支持forward:schemed uri。如果调用了回退,请求将被转发到与URI匹配的控制器。以下示例配置这样的回退:

spring:
  cloud:
    gateway:
      routes:
      - id: hystrix_route
        uri: lb://backing-service:8088
        predicates:
        - Path=/consumingserviceendpoint
        filters:
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/incaseoffailureusethis
        - RewritePath=/consumingserviceendpoint, /backingserviceendpoint

The FallbackHeaders GatewayFilter Factory

FallbackHeaders工厂允许您在转发到外部应用程序中的fallbackUri的请求头中添加Hystrix或Spring Cloud断路器执行异常详细信息,如下所示:

spring:
  cloud:
    gateway:
      routes:
      - id: ingredients
        uri: lb://ingredients
        predicates:
        - Path=//ingredients/**
        filters:
        - name: CircuitBreaker
          args:
            name: fetchIngredients
            fallbackUri: forward:/fallback
      - id: ingredients-fallback
        uri: http://localhost:9994
        predicates:
        - Path=/fallback
        filters:
        - name: FallbackHeaders
          args:
            executionExceptionTypeHeaderName: Test-Header

在本例中,运行断路器时发生执行异常后,请求将转发到localhost:9994上运行的应用程序中的回退终结点或处理程序。具有异常类型、消息和(如果可用)根原因异常类型和消息的头将由FallbackHeaders筛选器添加到该请求中。
您可以通过设置以下参数的值(以其默认值显示)覆盖配置中标题的名称:在这里插入图片描述

The MapRequestHeader GatewayFilter Factory

MapRequestHeader工厂接受fromHeadertoHeader参数。它创建一个新的命名头(toHeader),并从传入http请求的现有命名头(from header)中提取值。如果输入头不存在,则筛选器没有影响。如果新的命名头已经存在,则它的值将用新值进行扩展。以下示例配置MapRequestHeader:

spring:
  cloud:
    gateway:
      routes:
      - id: map_request_header_route
        uri: https://example.org
        filters:
        - MapRequestHeader=Blue, X-Request-Red

这会将X-Request-Red:头添加到下游请求,其中包含来自传入HTTP请求的blue头的更新值

The PrefixPath GatewayFilter Factory

前缀路径过滤器,由单个参数prefix构成

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

这将给所有匹配请求的路径加上/mypath前缀
所以对/hello的请求将被发送到/mypath/hello

The PreserveHostHeader GatewayFilter Factory

我们从字面意思可以知道:保护Host Header,其实就是保护请求头中的Host字段。PreserveHostHeader 不需要参数。
此过滤器将检查该请求属性,以确定是否应发送原始主机头,而不是由HTTP客户端确定的主机头。
该工厂没有任何参数

The RequestRateLimiter GatewayFilter Factory

RequestRateLimiter GatewayFilter请求速率限制器工厂。 是RateLimiter 的实现类,用它去决定当前请求是否允许继续执行。如果不允许继续执行,默认会返回一个 HTTP 429 - Too Many Requests (太多连接状态)。
这个filter采用 一个可选的keyResolver 参数 和 指定的速率限制器参数。
keyResolver 是实现keyResolver 接口的bean。在配置中,使用SpEL按名称引用bean。#{@mykeyresolver}是引用名为mykeyrolver的bean的SpEL表达式。下面的列表显示了keyrolver接口:

public interface KeyResolver {
    Mono<String> resolve(ServerWebExchange exchange);
}

KeyResolver接口允许一个可拔插策略去驱动如何限制请求。
有一个默认实现:

public class PrincipalNameKeyResolver implements KeyResolver {
	public static final String BEAN_NAME = "principalNameKeyResolver";

	@Override
	public Mono<String> resolve(ServerWebExchange exchange) {
		return exchange.getPrincipal().map(Principal::getName)
				.switchIfEmpty(Mono.empty());
	}
}

从上面的代码可以看出:默认的keyResolver 的实现是从 ServerWebExchange 取得Principal 并且回调Principal.getName() 方法。
默认情况下,如果 KeyResolver 没有找到一个key,那么请求将会被拒绝。当然,可以通过 spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key (true or false) 以及 spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code 属性来设置。

The Redis RateLimiter

Redis的实现是基于在Stripe完成的工作。它需要使用spring-boot-starter-data-redis-reactive 的包。实现原理为令牌桶算法。

属性

redis-rate-limiter.replenishRate : 希望每秒中允许用户执行多少请求,不会丢弃任何请求
redis-rate-limiter.burstCapacity : 允许用户在一秒内执行的最大请求数。将此值设置为0,将阻止所有请求。
redis-rate-limiter.requestedTokens : 一个请求需要花费多少令牌。这是每个请求从bucket中获取的令牌数,默认为1。

jar包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

java类

@Bean
KeyResolver userKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}

yml配置

spring:
  cloud:
    gateway:
      routes:
        - id: request_hrate_limiter
          uri: http://localhost:9999
          Predicates:
            Method= GET
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 2
                redis-rate-limiter.burstCapacity: 2
                redis-rate-limiter.requestedTokens: 1
  redis:
    host: 127.0.0.1
    port: 6379

为实现一个稳定的速率,通常将上述两个属性[replenishRat、burstCapacity]设置成相同的值,将burstCapacity 设置大于 replenishRate 可以允许临时暴发。在这种情况下,需要在突发之间允许速率限制器一段时间(根据replenishRate ),因为连续两次突发可能导致请求被丢弃(HTTP 429 - Too Many Requests)
另外,如果我们自己定义限流的策略,可以这样来配置yaml
【myRateLimiter、userKeyResolver】这里都是Spring中的bean,可以自己定义

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            rate-limiter: "#{@myRateLimiter}"
            key-resolver: "#{@userKeyResolver}"

The RedirectTo GatewayFilter Factory

RedirectTo GatewayFilter重定向工厂采用两个参数:status 和 url。这个状态码需要是一个300系列的重定向的HTTP状态码。例如:301. url应该是一个有效的地址,将设置为头部的Location的值。

spring:
  cloud:
    gateway:
      routes:
        - id: request_hrate_limiter
          uri: http://localhost:9999
          Predicates:
            Method= GET
          filters:
            - RedirectTo= 302, http://www.163.com

访问http://localhost:8080/redirectTo 路径时,并不会映射到http://localhost:9999/redirectTo.而是被转发到了http://www.163.com.且状态为302。

The RemoveRequestHeader GatewayFilter Factory

RemoveequestHeader GatewayFilter工厂接受一个名称参数。它是要删除的头的名称。以下列表配置RemoveRequestHeader网关筛选器:

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

这将在X-Request-Foo头被发送到下游之前删除它

RemoveResponseHeader GatewayFilter Factory

在返回客户端之前,删除指定响应头的数据。RemoveResponseHeader GatewayFilter 工厂采用一个参数:name .

spring:
  cloud:
    gateway:
      routes:
        - id: remove_response_header
          uri: http://localhost:9999
          Predicates:
            Method= GET
          filters:
            - RemoveResponseHeader=Content-Type

上面的配置可以从响应头中删除 Content-Type 头信息,然后将其返回到客户端。
要删除任何类型的敏感信息,你可以需要配置这个filter在你需要的任何路由上,当然,我们可以在配置文件中配置spring.cloud.gateway.default-filters, 那么可以引用在所有的路由上。

The RemoveRequestParameter GatewayFilter Factory

RemoveRequestParameter GatewayFilter 工厂采用一个参数:name . 指定请求参数将会被删除。

spring:
  cloud:
    gateway:
      routes:
      - id: removerequestparameter_route
        uri: https://example.org
        filters:
        - RemoveRequestParameter=red

这将在red参数被发送到下游的服务之前删除它。

The RewritePath GatewayFilter Factory

RewritePath Gateway采用路径 正常表达式和替换参数。使用正则表达式可以灵活地重写请求路径。

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://example.org
        predicates:
        - Path=/foo/**
        filters:
        - RewritePath=/red(?<segment>/?.*), $\{segment}

对于/red/blue的请求路径,这会在发出下游请求之前将路径设置为/blue。注意, 应该替换为 \ ,因为YAML规范。

RewriteLocationResponseHeader GatewayFilter Factory

RewriteLocationResponseHeader GatewayFilter 工厂 用来重写 响应头的Location 的值,以摆脱后端特定的详细信息。这需要 stripVersionMode , locationHeaderName , hostValue 和 protocolsRegex 参数。

spring:
  cloud:
    gateway:
      routes:
      - id: rewritelocationresponseheader_route
        uri: http://example.org
        filters:
        - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,

示例:对于请求api.example.com/some/object/name. Location 响应头的值object-service.prod.example.net/v2/some/object/id 将会被重写为api.example.com/some/object/id。
解释:由于hostValue 和 protocolsRegex 参数都没有提供,所以使用原请求的host,并且stripVersionMode 选择的是AS_IN_REQUEST , 所以在原请求路径不包含版本时,将版本剥离删除。
步骤:

  1. api.example.com/some/object/name
  2. api.example.com/v2/some/object/id
  3. api.example.com/some/object/id

参数stripVersionMode 具有以下可选值:NEVER_STRIP , AS_IN_REQUEST (默认) , ALWAYS_STRIP.
NEVER_STRIP 即使原始请求路径不包含任何版本,也不会剥离版本。
AS_IN_REQUEST 仅当原始请求不包含版本时,版本才会被剥离。
ALWAYS_STRIP 即使原始请求路径包含版本,也会删除版本。
参数 hostValue (如果提供) 将用于替换 host:port 响应 Location 头的一部分。如果未提供,Host 则将作为请求头的值使用。
参数 protocolsRegex 必须是有效的正则表达式字符串,协议名称将与该regex 匹配。如果不匹配,过滤器将不执行任何操作。默认值为 http|https|ftp|ftps.

The RewriteResponseHeader GatewayFilter Factory

RewriteResponseHeader GatewayFilter 工厂采用三个参数,分别为:name, regexp 和 replacement . 它使用Java正则表达式以灵活的方式来重写响应头的值。

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

对于响应头值 /42?user=ford&password=omg!what&flag=true , 在下游请求执行之后将被设置为 /42?user=ford&password=***&flag=true ,在YAML文件中,需要使用   \ 来表示 .

The SaveSession GatewayFilter Factory

SaveSession GatewayFilter 工厂在向下游转发调用之前会强制执行 WebSession::save 操作。 这在将Spring Session之类的东西与惰性数据存储一起使用时特别有用,并且需要确保在进行转发呼叫之前已保存会话状态。

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

如果您将Spring Security与Spring Session 集成在一起,并且想要确保安全性详细信息已转发到远程进程,那么这一点至关重要。

The SecureHeaders GatewayFilter Factory

SecureHeaders GatewayFilter 工厂添加了许多头到响应中。
添加了以下标头(以及默认值):
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
要更改默认值,请在spring.cloud.gateway.filter.secure-headers名称空间中设置适当的属性:
xss-protection-header
strict-transport-security
x-frame-options
x-content-type-options
referrer-policy
content-security-policyx
x-download-options
x-permitted-cross-domain-policies
若要禁用默认值,请使用逗号分隔的值设置spring.cloud.gateway.filter.secure-headers.disable属性。下面的示例演示了如何执行此操作:

spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security

The SetPath GatewayFilter Factory

SetPath GatewayFilter 采用路径template 参数。通过允许路径的模板片段,提供了一种操作请求路径的简单方法。这使用了Spring Framework 中的uri模板。允许多个匹配片段。

spring:
  cloud:
    gateway:
      routes:
        - id: remove_response_parameter
          uri: http://localhost:9999
          Predicates:
            - Path= /set/{subUrl}
          filters:
            - SetPath= /{subUrl}

对于请求路径 /set/path ,路径会被设置为/path 然后在转发到下游请求。

The SetRequestHeader GatewayFilter Factory

SetRequestHeader GatewayFilter 工厂采用 name 和 value 参数。

spring:
  cloud:
    gateway:
      routes:
        - id: set_request_header
          uri: http://localhost:9999
          Predicates:
            - Method=GET
          filters:
            - SetRequestHeader=username,admin

以上设置,可以将请求头中的username 的原来值修改为admin.
SetRequestHeader和前面的AddRequestHeader不同,这个是将原来的值替换为配置的值。
也可以动态配置

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

The SetResponseHeader GatewayFilter Factory

SetResponseHeader GatewayFilter 工厂采用两个参数:name 和 value .

spring:
  cloud:
    gateway:
      routes:
        - id: set_request_header
          uri: http://localhost:9999
          Predicates:
            - Method=GET
          filters:
            - SetResponseHeader= X-Response-username,admin

这个过滤器主要是将 响应头中的 X-Response-username 替换为 admin .同样也可以使用路径参数动态传递。

The SetStatus GatewayFilter Factory

SetStatus GatewayFilter工厂采用一个参数:status , 这个参数必须是一个有效的Spring HttpStatus . 它可以是整数值 404 或是枚举的字符串表示形式NOT_FOUND.

spring:
  cloud:
    gateway:
      routes:
        - id: set_status1
          uri: http://localhost:9999
          Predicates:
            - Method=GET
          filters:
            - SetStatus= NOT_FOUND
        - id: set_status2
          uri: http://localhost:9999
          Predicates:
            - Method=GET
          filters:
            - SetStatus= 404

无论上述情况的哪一种,响应的HTTP状态都讲设置为404.
SetStatus GatewayFilter可以被 配置为响应头中从代理请求返回原始HTTP状态码,如果使用以下属性配置header,则会将其添加到响应头中:

spring:
  cloud:
    gateway:
      set-status:
        original-status-header-name: original-http-status

The StripPrefix GatewayFilter Factory

StripPrefix GatewayFilter工厂采用一个参数:part , 这个参数在请求转发到下游之前去除路径的前 part 部分。

spring:
  cloud:
    gateway:
      routes:
        - id: strip_prefix
          uri: http://localhost:9999
          Predicates:
            - Method=GET
          filters:
            - StripPrefix= 2

根据以上配置,可以将/user/name/stripPrefix 地址 切除前面两段,所以最后转发到下游的地址是/stripPrefix.

The Retry GatewayFilter Factory

重试机制,参数如下:

  • retries
    应该重试的次数,默认3次
  • statuses
    应该重试的状态码【org.springframework.http.HttpStatus】默认500
  • methods
    应该重试的异常方法【org.springframework.http.HttpMethod】默认get方法
  • series
    应该重试的异常状态码详情【org.springframework.http.HttpStatus.Series】
  • exceptions
    应该重试的异常列表,默认IOException和TimeOutException
  • backoff
    回退因子,自行了解,默认disabled
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
            methods: GET,POST
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false

The RequestSize GatewayFilter Factory

当请求大小高于允许的限制大小时,RequestSize GatewayFilter工厂将会阻止转发到下游服务。过滤器将RequestSize 参数作为请求的允许大小限制(以字节为单位)

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

当请求由于大小而被拒绝时,RequestSize GatewayFilter 工厂将响应状态设置为 413 Payload Too Large 并带有head名为errorMessage 的数据。如下:

errorMessage: Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0MB

【如果未在路由定义中作为过滤器参数提供,则默认请求大小设置为5MB】

Modify a Request Body GatewayFilter Factory

这个过滤器用于在将请求转发到下游服务之前,将请求体进行修改。
注意:只能通过java来配置此过滤器。

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org")
            .filters(f -> f.prefixPath("/httpbin")
                .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
                    (exchange, s) -> return Mono.just(new Hello(s.toUpperCase())))).uri(uri))
        .build();
}

static class Hello {
    String message;

    public Hello() { }

    public Hello(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Modify a Response Body GatewayFilter Factory

该过滤器在响应发送会客户端之前,对响应体进行修改。同样也只支持Java配置。

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org")
            .filters(f -> f.prefixPath("/httpbin")
                .modifyResponseBody(String.class, String.class,
                    (exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri)
        .build();
}

Default Filters

如果想添加一个过滤器去应用在所有的路由上,可以使用 spring.cloud.gateway.default-filters 来配置,这个属性接收一个Filter列表。

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

四、GlobalFilters工厂簇

GlobalFilter接口与GatewayFilter具有相同的签名。这些是有条件应用于所有路由的特殊筛选器。
【此接口及其用法在将来的里程碑版本中可能会发生更改】

组合GlobalFilter和 GatewayFilter顺序

当请求与路由匹配时,筛选web处理程序会将GlobalFilter的所有实例和GatewayFilter的所有路由特定实例添加到筛选器链中。这个组合的过滤链是按org.springframework.core.Ordered接口排序的,您可以通过实现getOrder()方法来设置这个接口。

由于SpringCloudGateway区分了过滤器逻辑执行的“pre”和“post”阶段(请参见其工作原理),因此优先级最高的过滤器是“pre”阶段的第一个过滤器,也是“post”阶段的最后一个过滤器。

@Bean
public GlobalFilter customFilter() {
    return new CustomGlobalFilter();
}

public class CustomGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

Forward Routing Filter

ForwardRoutingFilterexchange属性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR中查找URI
如果URL有一个转发方案(例如forward:///localendpoint),它将使用Spring DispatcherHandler来处理请求。请求URL的路径部分将被前向URL中的路径覆盖。
未修改的原始URL将附加到ServerWebExchangeUtils.GATEWAY_original_REQUEST_URL_ATTR属性中的列表中。

The LoadBalancerClientFilter

LoadBalancerClientFilter在名为ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTRexchange属性中查找URI。如果URL有一个lb方案(例如lb://myservice),它使用Spring Cloud LoadBalancerClient将名称(本例中为myservice)解析为实际的主机和端口,并替换同一属性中的URI。未修改的原始URL将附加到ServerWebExchangeUtils.GATEWAY_original_REQUEST_URL_ATTR属性中的列表中。
过滤器还会在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR属性中查看它是否等于lb。如果是,则应用相同的规则。以下列表配置了LoadBalancerClientFilter

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

默认情况下,当在LoadBalancer中找不到服务实例时,将返回503。
spring.cloud.Gateway.loadbalancer.use404=true,可以将网关配置为返回404。
该默认在引擎盖下使用阻塞的功能区LoadBalancerClient。我们建议您改用ReactiveLoadBalancerClientFilter。可以通过将spring.cloud.loadbalancer.ribbon.enabled的值设置为false来切换。

ReactiveLoadBalancerClientFilter

ReactiveLoadBalancerClientFilter在名为ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTRexchange属性中查找URI。如果URL有一个lb方案(例如lb://myservice),它使用Spring Cloud reactor负载均衡器将名称(本例中为myservice)解析为实际的主机和端口,并替换同一属性中的URI。未修改的原始URL将附加到ServerWebExchangeUtils.GATEWAY_original_REQUEST_URL_ATTR属性中的列表中。过滤器还会在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR属性中查看它是否等于lb。如果是,则应用相同的规则。下面的列表配置了一个ReactiveLoadBalancerClientFilter

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

默认情况下,当在LoadBalancer中找不到服务实例时,将返回503。
spring.cloud.Gateway.loadbalancer.use404=true,可以将网关配置为返回404。

The Netty Routing Filter

如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange属性中的URL具有http或https方案,则运行Netty路由筛选器。它使用Netty HttpClient发出下游代理请求。响应放在ServerWebExchangeUtils.CLIENT_response_ATTR exchange属性中,以便在以后的筛选器中使用。(还有一个实验性的WebClientHttpRoutingFilter,它执行相同的功能,但不需要Netty。)

The Netty Write Response Filter

如果在ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR exchange属性中存在Netty HttpClientResponse,则NettyWriteResponseFilter将运行。它在所有其他筛选器完成并将代理响应写入网关客户端响应后运行。(还有一个实验性的WebClientWriteResponseFilter,它执行相同的功能,但不需要Netty

The RouteToRequestUrl Filter

If there is a Route object in the ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR exchange attribute, the RouteToRequestUrlFilter runs. It creates a new URI, based off of the request URI but updated with the URI attribute of the Route object. The new URI is placed in the ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange attribute`.

If the URI has a scheme prefix, such as lb:ws://serviceid, the lb scheme is stripped from the URI and placed in the ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR for use later in the filter chain.

The Websocket Routing Filter

如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange属性中的URL具有wswss方案,则运行websocket路由rilter。它使用Spring WebSocket基础设施将WebSocket请求转发到下游。
可以通过在URI前面加上lb来负载平衡websockets,例如lb:ws://serviceid。

spring:
  cloud:
    gateway:
      routes:
      # SockJS route
      - id: websocket_sockjs_route
        uri: http://localhost:3001
        predicates:
        - Path=/websocket/info/**
      # Normal Websocket route
      - id: websocket_route
        uri: ws://localhost:3001
        predicates:
        - Path=/websocket/**

网关Metrics监控

启用网关度量监控,新增包spring-boot-starter-actuator依赖,
只要spring.cloud.gateway.metrics.enabled的值不是false就会开启
routeId: The route ID.
routeUri: The URI to which the API is routed.
outcome: The outcome, as classified by HttpStatus.Series.
status: The HTTP status of the request returned to the client.
httpStatusCode: The HTTP Status of the request returned to the client.
httpMethod: The HTTP method used for the request.
然后,可以从/actuator/metrics/gateway.requests中获取这些度量,并且可以很容易地与Prometheus集成以创建Grafana仪表板。

要开启 prometheus endpoint, 添加依赖micrometer-registry-prometheus

五、HttpHeadersFilters

HttpHeadersFilters在向下游发送请求之前应用于请求,例如在NetTroutingFilter中。

Forwarded Headers Filter

Forwarded Headers筛选器创建要发送到下游服务的转发头。它将当前请求的主机头、方案和端口添加到任何现有的转发头。

RemoveHopByHop Headers Filter

RemoveHopByHop头过滤器从转发的请求中删除头。删除的头的默认列表来自IETF。在这里插入图片描述若要更改此设置,请将spring.cloud.gateway.filter.remove-non-proxy-headers.headers属性设置为要删除的头名称列表。

XForwarded Headers Filter

创建各种X-Forwarded-*头以发送到下游服务。
它使用当前请求的主机头、方案、端口和路径来创建各种头。
在这里插入图片描述
六、配置启动
由RouteDefinitionLocator实例的集合驱动。以下列表显示了RouteDefinitionLocator接口的定义:

public interface RouteDefinitionLocator {
    Flux<RouteDefinition> getRouteDefinitions();
}

关于网关的启动入口,我们先在找到jar包spring-cloud-starter-gateway基本上模块的初始化都在这里,我们随后进去后找到
GatewayAutoConfiguration类,这里面,很多前面提到的类都有以@Bean的方式,注入到spring容器,包括yaml里面route的写法,以及filters都可以找到对应的类,如果对执行流程有兴趣,再自行了解,不做说明

七、Route元数据配置

spring:
  cloud:
    gateway:
      routes:
      - id: route_with_metadata
        uri: https://example.org
        metadata:
          optionName: "OptionValue"
          compositeObject:
            name: "value"
          iAmNumber: 1
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// get all metadata properties
route.getMetadata();
// get a single metadata property
route.getMetadata(someKey);

八、Http超时设置

全局超时

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000
        response-timeout: 5s

单路由超时

spring:
  cloud:
    gateway:
      routes:
      - id: per_route_timeouts
        uri: https://example.org
        predicates:
          - name: Path
            args:
              pattern: /delay/{timeout}
        metadata:
          response-timeout: 200
          connect-timeout: 200

也可以在java中手动设置

import static org.springframework.cloud.gateway.support.RouteMetadataUtils.CONNECT_TIMEOUT_ATTR;
import static org.springframework.cloud.gateway.support.RouteMetadataUtils.RESPONSE_TIMEOUT_ATTR;

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeBuilder){
	return routeBuilder.routes()
           .route("test1", r -> {
               return r.host("*.somehost.org").and().path("/somepath")
                        .filters(f -> f.addRequestHeader("header1", "header-value-1"))
                        .uri("http://someuri")
                        .metadata(RESPONSE_TIMEOUT_ATTR, 200)
                        .metadata(CONNECT_TIMEOUT_ATTR, 200);
               })
               .build();
      }

Stream流式route配置

// static imports from GatewayFilters and RoutePredicates
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
    return builder.routes()
            .route(r -> r.host("**.abc.org").and().path("/image/png")
                .filters(f ->
                        f.addResponseHeader("X-TestHeader", "foobar"))
                .uri("http://httpbin.org:80")
            )
            .route(r -> r.path("/image/webp")
                .filters(f ->
                        f.addResponseHeader("X-AnotherHeader", "baz"))
                .uri("http://httpbin.org:80")
                .metadata("key", "value")
            )
            .route(r -> r.order(-1)
                .host("**.throttle.org").and().path("/get")
                .filters(f -> f.filter(throttle.apply(1,
                        1,
                        10,
                        TimeUnit.SECONDS)))
                .uri("http://httpbin.org:80")
                .metadata("key", "value")
            )
            .build();
}

Cors配置

可以配置网关来控制CORS行为。“全局”CORS配置是URL模式到Spring框架CORS configuration的映射。以下示例配置CORS:

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
            - GET

在前面的示例中,对于所有GET请求路径,允许来自docs.spring.io的请求发出CORS请求。
要为某些网关路由断言未处理的请求提供相同的CORS配置,请将spring.cloud.gateway.globalcors.add-To-simple-url-handler-mapping属性设置为true。当您试图支持CORS飞行前请求,并且您的路由谓词由于HTTP方法是选项而没有求值为true时,这非常有用。

Actuator API

开启第三方监控,暴露需要监控的的api

management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway

九、问题定位

控制日志输出级别为Deubg或者Info
在这里插入图片描述

十、开发指南

1.自定义Route断言

为了编写路由断言,您需要实现RoutePredicateFactory。有一个名为AbstractRoutePredicateFactory的抽象类,您可以对其进行扩展。
MyRoutePredicateFactory.java

public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {

    public MyRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        // grab configuration from Config object
        return exchange -> {
            //grab the request
            ServerHttpRequest request = exchange.getRequest();
            //take information from the request to see if it
            //matches configuration.
            return matches(config, request);
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

2.自定义GatewayFilter过滤器

一定得实现GatewayFilterFactory,我们可以通过继承名为AbstractGatewayFilterFactory的抽象类。以下示例说明了如何执行此操作:
1.PreGatewayFilterFactory.java

public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {

    public PreGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            //If you want to build a "pre" filter you need to manipulate the
            //request before calling chain.filter
            ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
            //use builder to manipulate the request
            return chain.filter(exchange.mutate().request(request).build());
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

2.PostGatewayFilterFactory.java

public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {

    public PostGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                ServerHttpResponse response = exchange.getResponse();
                //Manipulate the response in some way
            }));
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

3.自定义GlobalFilter过滤器

要编写自定义全局筛选器,必须实现全局筛选器接口。这会将筛选器应用于所有请求。
以下示例分别演示如何设置全局前置和后置筛选器:

@Bean
public GlobalFilter customGlobalFilter() {
    return (exchange, chain) -> exchange.getPrincipal()
        .map(Principal::getName)
        .defaultIfEmpty("Default User")
        .map(userName -> {
          //adds header to proxied request
          exchange.getRequest().mutate().header("CUSTOM-REQUEST-HEADER", userName).build();
          return exchange;
        })
        .flatMap(chain::filter);
}

@Bean
public GlobalFilter customGlobalPostFilter() {
    return (exchange, chain) -> chain.filter(exchange)
        .then(Mono.just(exchange))
        .map(serverWebExchange -> {
          //adds header to response
          serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",
              HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode()) ? "It worked": "It did not work");
          return serverWebExchange;
        })
        .then();
}

十一、踩坑记录

1.服务代理路由设置的2种方式

gateway:
      #开启基于注册中心的路由表且支持实例名小写
      discovery:
        ## 是否可以通过其他服务的serviceId来转发到具体的服务实例。默认为false,
        locator:
          enabled: false
          lower-case-service-id: true
      routes:
        - id: provider
          uri: lb://provider
          predicates:
            - Path=/gateway/pvs/**
          filters:
            - RewritePath=/gateway/pvs/(?<remaining>.*),/provider/${remaining}
            # hystrix服务降级配置
            - name: Hystrix
              args:
                name: fallbackcmd
                fallbackUri: forward:/fallback?project=provider

在看了官网的长篇介绍,自己实践了一下,发现网关代理的服务路由,理解上有些偏差,而且存在2种配置的方式,主要体现为locator的值的配置。

locator的值:
true:可以通过其他服务的serviceId来转发到具体的服务实例。 【http://Gateway_HOST:Gateway_PORT/大写的serviceId/**,需要小写可以设置lower-case-service-id: true】,一般情况下,会和StripPrefix过滤器搭配使用
false: 不可以通过其他服务的serviceId来转发到具体服务,其中微服务应用名默认大写访问,一般会和rewrithPath过滤器搭配使用【我自己用的就是这个,灵活度较高】
贴一下我自己的配置:

spring:
	gateway:
      #开启基于注册中心的路由表且支持实例名小写
      discovery:
        ## 是否可以通过其他服务的serviceId来转发到具体的服务实例。默认为false,
        locator:
          enabled: false
          # 是否支持serviceId小写模式
          lower-case-service-id: true
      routes:
        - id: provider
          uri: lb://provider
          predicates:
            - Path=/gateway/pvs/**
          filters:
            - RewritePath=/gateway/pvs/(?<remaining>.*),/provider/${remaining}
            # hystrix服务降级配置
            - name: Hystrix
              args:
                name: fallbackcmd
                fallbackUri: forward:/fallback?project=provider
            # 限流过滤器,使用gateway内置令牌算法

判断路由代理成功的日志输出:

```powershell
11:17:35.008 [reactor-http-nio-2] TRACE org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter - Weights attr: {}
11:17:35.011 [reactor-http-nio-2] TRACE org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory - Pattern "[/get]" does not match against value "/gateway/cns/simple/simple_invoke_service"
11:17:35.011 [reactor-http-nio-2] TRACE org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory - Pattern "[/gateway/pvs/**]" does not match against value "/gateway/cns/simple/simple_invoke_service"
11:17:35.012 [reactor-http-nio-2] TRACE org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory - Pattern "/gateway/cns/**" matches against value "/gateway/cns/simple/simple_invoke_service"
11:17:35.012 [reactor-http-nio-2] DEBUG org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping - Route matched: consumer
11:17:35.012 [reactor-http-nio-2] DEBUG org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping - Mapping [Exchange: GET http://localhost:8080/gateway/cns/simple/simple_invoke_service] to Route{id='consumer', uri=lb://consumer, order=0, predicate=org.springframework.cloud.gateway.support.ServerWebExchangeUtils$$Lambda$379/1377593328@3810d724, gatewayFilters=[OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory$$Lambda$741/1293177207@609cd2d2, order=1}, OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.HystrixGatewayFilterFactory$$Lambda$388/1171489125@5a0ed751, order=2}]}
11:17:35.012 [reactor-http-nio-2] DEBUG org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping - [e6eb6095] Mapped to org.springframework.cloud.gateway.handler.FilteringWebHandler@1248789c
11:17:35.012 [reactor-http-nio-2] DEBUG org.springframework.cloud.gateway.handler.FilteringWebHandler - Sorted gatewayFilterFactories: [OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RemoveCachedBodyFilter@4d4600fb}, order=-2147483648}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@6f2bf657}, order=-2147482648}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@6ed87ccf}, order=-1}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardPathFilter@4d2950ed}, order=0}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.GatewayMetricsFilter@51aaa9d4}, order=0}, OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory$$Lambda$741/1293177207@609cd2d2, order=1}, OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.HystrixGatewayFilterFactory$$Lambda$388/1171489125@5a0ed751, order=2}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@7352418c}, order=10000}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@46ff1aad}, order=10100}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@3095d06b}, order=2147483646}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyRoutingFilter@6c2fea95}, order=2147483647}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardRoutingFilter@60ba6631}, order=2147483647}]
11:17:35.013 [reactor-http-nio-2] TRACE org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter - RouteToRequestUrlFilter start
11:17:35.014 [reactor-http-nio-2] TRACE org.springframework.cloud.gateway.filter.LoadBalancerClientFilter - LoadBalancerClientFilter url before: lb://consumer/cns/simple/simple_invoke_service
11:17:35.014 [reactor-http-nio-2] TRACE org.springframework.cloud.gateway.filter.LoadBalancerClientFilter - LoadBalancerClientFilter url chosen: http://10.4.87.94:9000/cns/simple/simple_invoke_service
11:17:35.016 [reactor-http-nio-2] TRACE org.springframework.cloud.gateway.filter.NettyRoutingFilter - outbound route: 96f96ce3, inbound: [e6eb6095] 
11:17:36.028 [HystrixTimer-3] DEBUG org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping - [e6eb6095] Mapped to public com.blue.common.exception.JsonResult com.blue.gateway.config.ServiceFallBack.fallback(java.lang.String)
11:17:36.032 [HystrixTimer-3] DEBUG org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler - Using 'application/json;charset=UTF-8;q=0.8' given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8] and supported [application/json;charset=UTF-8, application/*+json;charset=UTF-8, text/event-stream]
11:17:36.032 [HystrixTimer-3] DEBUG org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler - [e6eb6095] 0..1 [com.blue.common.exception.JsonResult]
11:17:36.039 [reactor-http-nio-2] TRACE org.springframework.cloud.gateway.filter.GatewayMetricsFilter - gateway.requests tags: [tag(httpMethod=GET),tag(httpStatusCode=NA),tag(outcome=CUSTOM),tag(routeId=consumer),tag(routeUri=lb://consumer),tag(status=CUSTOM)]

代理的服务内部的访问url也是会打印出来的哦!

2.redis的限流配置

yml文件

- name: RequestRateLimiter
              args:
                # 令牌桶每秒填充平均速率,即行等价于允许用户每秒处理多少个请求平均数
                redis-rate-limiter.replenishRate: 1
                # 令牌桶的容量,允许在一秒钟内完成的最大请求数
                redis-rate-limiter.burstCapacity: 3
                # 每个请求耗费的令牌数量,默认为1
                redis-rate-limiter.requestedTokens: 1
                # 用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。
                key-resolver: "#{@ipKeyResolver}"

在这里插入图片描述

java配置bean

@Configuration
public class RequestRateLimiterConfig {

    @Bean
    @Primary
    KeyResolver apiKeyResolver() {
        //按URL限流,即以每秒内请求数按URL分组统计,超出限流的url请求都将返回429状态
        return exchange -> Mono.just(exchange.getRequest().getPath().toString());
    }

    @Bean
    KeyResolver userKeyResolver() {
        //按用户限流
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    }

    @Bean
    KeyResolver ipKeyResolver() {
        //按IP来限流
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
}

jmeter多线程测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

查看redis的存储值

为了方便查看,我们将redis的数据库默认配置为0的索引库
在这里插入图片描述
在这里插入图片描述

3.查看gateway网关信息

localhost:xxx:/contex-path/actuator/gateway/【GatewayControllerEndpoint类下的接口】

发布了17 篇原创文章 · 获赞 4 · 访问量 3382

猜你喜欢

转载自blog.csdn.net/u013553309/article/details/104802378