diff --git a/spring/Spring Cloud/Spring Cloud gateway.md b/spring/Spring Cloud/Spring Cloud gateway.md index 7b9d3ab..39d9551 100644 --- a/spring/Spring Cloud/Spring Cloud gateway.md +++ b/spring/Spring Cloud/Spring Cloud gateway.md @@ -87,4 +87,359 @@ spring: ``` 上述cookie_route会匹配请求中含有name为chocolate的cookie,并且cookie值满足`ch.p`正则表达式的请求。 ### Header Route Predicate Factory -Header Route Predicate Factory接收两个参数,`header`和`regexp`。 +Header Route Predicate Factory接收两个参数,`header`和`regexp`(regexp是正则表达式)。该predicate会匹配一个拥有指定名称header的请求,且header对应的值要满足regexp表达式。 +如下示例显示了header route predicate的用法: +```yml +spring: + cloud: + gateway: + routes: + - id: header_route + uri: https://example.org + predicates: + - Header=X-Request-Id, \d+ +``` +### Host Route Predicate Factory +Host Route Predicate Factory接收一个参数:一个pattern列表。pattern是ant-style并用`.`作为分隔符。该predicate会匹配`Host`header,示例如下所示: +```yml +spring: + cloud: + gateway: + routes: + - id: host_route + uri: https://example.org + predicates: + - Host=**.somehost.org,**.anotherhost.org +``` +URI template 变量例如`{sub}.myhost.org`也支持。 +该route会匹配如下请求:headers中包含name为Host的header,并且Host header的值为`www.somehost.org`,`beta.somehost.org`,`www.anotherhost.org`等形式 +### Method Route Predicate Factory +Method Route Predicate Factory接收一个`methods`参数,其指定了匹配的HTTP METHOD. 如下示例指定了一个method route predicate示例: +```yml +spring: + cloud: + gateway: + routes: + - id: method_route + uri: https://example.org + predicates: + - Method=GET,POST +``` +该predicate匹配method为GET或POST的任意请求。 +### Path Route Predicate Factory +Path Route Predicate Factory接收两个参数,一个PathMatcher Pattern的列表,和一个可选的matchTrailingSlash(默认设置为true)。 +如下实例配置了一条path route predicate: +```yml +spring: + cloud: + gateway: + routes: + - id: path_route + uri: https://example.org + predicates: + - Path=/red/{segment},/blue/{segment} +``` +上述配置的route能够匹配/red/1或/red/1/、/red/blue或/blue/green. +如果`matchTrailingSlash`被设置为false,那么/red/1/将不会被匹配到。 +该predicate将URI template变量(例如segment)解析为name、value键值对并且放到ServerWebExchange.getAttributes()中。这些值可以被GatewayFilter factories使用。 +可以通过如下的工具类方法来对这些变量进行访问,按如下示例所示: +```java +Map uriVariables = ServerWebExchangeUtils.getUriTemplateVariables(exchange); + +String segment = uriVariables.get("segment"); +``` +### Query Route Predicate Factory +Query Route Predicate Factory接收两个参数:必填参数param和可选参数regexp,示例如下所示: +```yml +spring: + cloud: + gateway: + routes: + - id: query_route + uri: https://example.org + predicates: + - Query=green +``` +上述路由配置,匹配请求参数中含有green参数的请求 +```yml +spring: + cloud: + gateway: + routes: + - id: query_route + uri: https://example.org + predicates: + - Query=red, gree. +``` +该route则是匹配请求参数含有red,并且其value满足`gree.`正则表达式的请求。 +### RemoteAddr Route Predicate Factory +RemoteAddr route predicate factory接收一个`sources`列表(列表最小长度为1),列表元素为ipv4或ipv6字符串,例如`192.168.0.1/1`. +如下显示了一个RemoteAddr route predicate示例: +```yml +spring: + cloud: + gateway: + routes: + - id: remoteaddr_route + uri: https://example.org + predicates: + - RemoteAddr=192.168.1.1/24 +``` +该route匹配如下请求:如果请求的remote addr满足表达式,例如`192.168.1.10`。 +#### 修改Remote Addr的解析方式 +默认情况下,RemoteAddr predicate factory的解析方式是使用请求的remote address。但是,如果Spring Cloud Gateway如果位于proxy layer之后,那么remote address匹配的不是实际的client ip。 +可以通过自定义`RemoteAddressResolver`来自定义remote address的解析方式。Spring Cloud Gateway附带了一个非默认的remote address reslover,该reslover基于` X-Forwarded-For`header进行解析,该resolver是`XForwardedRemoteAddressResolver`。 +XForwardedRemoteAddressResolver有两个静态的构造器方法,分别使用了两种不同的安全方式: +- `XForwardedRemoteAddressResolver::trustAll`:返回一个RemoteAddressResolver,会一直从`X-Forwarded-For`中取第一个ip address。该方法很容易收到欺骗,因为恶意客户端程序会设置`X-Forwarded-For`字段的初始值,而此时reslover会接收虚假设置的值。 +- `XForwardedRemoteAddressResolver::maxTrustedIndex`:接收一个index,该index和Spring Cloud Gateway之前运行的受信任设施的数量相关。 + +如存在如下header: +```yml +X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3 +``` +如下maxTrustedIndex会产生的remote address将如下所示: +| maxTrustedIndex | result | +| :-: | :-: | +| [Integer.MIN_VALUE,0] | 该范围输入不合法 | +| 1 | 0.0.0.3 | +| 2 | 0.0.0.2 | +| 3 | 0.0.0.1 | +| [4, Integer.MAX_VALUE] | 0.0.0.1 | + +如下展示了如何通过java代码来完成相同的配置: +```java +RemoteAddressResolver resolver = XForwardedRemoteAddressResolver + .maxTrustedIndex(1); + +... + +.route("direct-route", + r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24") + .uri("https://downstream1") +.route("proxied-route", + r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24") + .uri("https://downstream2") +) +``` +### Weight Route Predicate Factory +Weight Route Predicate Factory接收两个参数:`group`和`weight`,weight将对每个group进行计算。如下示例配置了一个Weight Route Predicate: +```yml +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 +``` +该route将会把80%的负载转发到https://weighthigh.org,把20%的负载发送到https://weightlow.org +### XForwarded Remote Addr Route Predicate +XForwarded Remote Addr Route Predicate接收一个`sources`列表,列表元素为ipv4或ipv6地址,例如`192.168.0.1/16`。 +该route predicate允许通过`X-Forwarded-For` header来过滤请求。 +该predicate可以和反向代理服务器(通常用作负载均衡或web应用防火墙)一起使用,只有当请求来源于这些受信ip地址列表时,请求才会被允许访问。 +```yml +spring: + cloud: + gateway: + routes: + - id: xforwarded_remoteaddr_route + uri: https://example.org + predicates: + - XForwardedRemoteAddr=192.168.1.1/24 +``` +上述route,只有当`X-Forwarded-For` header中包含例如`192.168.1.10`的ip时,请求才会被匹配。 + +## GatewayFilter Factory +Route filters 允许对进入的请求和外出的响应进行修改,Route Filter作用域为特定的route。Spring Cloud Gateway有许多内置的route filter。 +### AddRequestHeader GatewayFilter Factory +AddRequestHeader GatewayFilter Factory接收一个name和value参数,如下示例配置了一个AddRequestHeader GatewayFilter: +```yml +spring: + cloud: + gateway: + routes: + - id: add_request_header_route + uri: https://example.org + filters: + - AddRequestHeader=X-Request-red, blue +``` +上述配置对所有匹配的请求在下游请求头中添加了`X-Request-red:blue`header。 +AddRequestHeader可以使用用于匹配path或host的URI变量。URI变量可以在value中使用,并且在运行时自动拓展,如下示例配置了一个使用URI变量的`AddRequestHeader GatewayFilter`: +```yml +spring: + cloud: + gateway: + routes: + - id: add_request_header_route + uri: https://example.org + predicates: + - Path=/red/{segment} + filters: + - AddRequestHeader=X-Request-Red, Blue-{segment} +``` +### AddRequestHeadersIfNotPresent GatewayFilter Factory +AddRequestHeadersIfNotPresent GatewayFilter接收一个name和value对集合,name和value之间通过`:`进行分隔,如下示例配置了一个filter: +```yml +spring: + cloud: + gateway: + routes: + - id: add_request_headers_route + uri: https://example.org + filters: + - AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-2:green +``` +上述配置会添加两个headers`X-Request-Color-1:blue`和`X-Request-Color-2:green`到下游请求的headers中。该操作和`AddRequestHeader`类似,但是AddRequestHeadersIfNotPresent只会当header不存在时才进行添加。如果该header存在,那么会保留该header的原有值。 +> 如果要设置一个multi-valued header,可以使用该headerName多次,例如`AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-1:green` + +`AddRequestHeadersIfNotPresent`也支持URI变量,如下配置了一个使用URI变量的Gateway Filter: +```yml +spring: + cloud: + gateway: + routes: + - id: add_request_header_route + uri: https://example.org + predicates: + - Path=/red/{segment} + filters: + - AddRequestHeadersIfNotPresent=X-Request-Red:Blue-{segment} +``` +### AddRequestParameter GatewayFilter Factory +AddRequestParameter GatewayFilter Factory接收一个name和value参数,如下示例配置了一个filter: +```xml +spring: + cloud: + gateway: + routes: + - id: add_request_parameter_route + uri: https://example.org + filters: + - AddRequestParameter=red, blue +``` +上述配置会向下游请求中加入请求参数。 +AddRequestParameter GatewayFilter可以使用URI变量,使用URI变量的配置如下所示: +```yml +spring: + cloud: + gateway: + routes: + - id: add_request_parameter_route + uri: https://example.org + predicates: + - Host: {segment}.myhost.org + filters: + - AddRequestParameter=foo, bar-{segment} +``` +### AddResponseHeader GatewayFilter Factory +`AddResponseHeader GatewayFilter Factory接收一个name和value参数,如下配置了一个filter: +```yml +spring: + cloud: + gateway: + routes: + - id: add_response_header_route + uri: https://example.org + filters: + - AddResponseHeader=X-Response-Red, Blue +``` +该filter添加了`X-Response-Red:Blue` header到下游响应的headers中。 +`AddResponseHeader GatewayFilter`可以使用URI变量,如下实例展示了使用URI变量的配置: +```yml +spring: + cloud: + gateway: + routes: + - id: add_response_header_route + uri: https://example.org + predicates: + - Host: {segment}.myhost.org + filters: + - AddResponseHeader=foo, bar-{segment} +``` +### CircuitBreaker GatewayFilter Factory +CircuitBreaker GatewayFilter Factory使用了Spring Cloud CircuitBreaker API来将网关路由包装到断路器中。 +为了启用Spring Cloud CircuitBreaker filter,需要将`spring-cloud-starter-circuitbreaker-reactor-resilience4j`放到classpath路径下,如下示例配置了filter: +```xml +spring: + cloud: + gateway: + routes: + - id: circuitbreaker_route + uri: https://example.org + filters: + - CircuitBreaker=myCircuitBreaker +``` +### CacheRequestBody GatewayFilter Factory +有一些场景需要读取请求体,因为请求只能被读取一次,因此需要缓存请求体。可以使用CacheRequestBody filter来缓存请求体,在请求被发送到下游之前,并且可以从`exchange`属性中获取请求体。 +```xml +spring: + cloud: + gateway: + routes: + - id: cache_request_body_route + uri: lb://downstream + predicates: + - Path=/downstream/** + filters: + - name: CacheRequestBody + args: + bodyClass: java.lang.String +``` +上述配置获取请求体并且将请求体转为了String类型,后续可以通过`ServerWebExchange.getAttributes()`来获取,key为`ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR`. + +### DedupeResponseHeader GatewayFilter Factory +DedupeResponseHeader GatewayFilter factory接收一个name参数和一个可选的strategy参数,name是一个用空格分隔的list,list元素为header name。如下配置了一个filter示例: +```yml +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响应header中的重复值,当gateway cors逻辑和下游逻辑都添加了它们时。 +DedupeResponseHeader还有一个可选的strategy参数,默认为RETAIN_FIRST,还可以是RETAIN_LAST和RETAIN_UNIQUE。 + +### 默认filters +如果想要添加一个filter并将其应用到所有的routes中,可以使用`spring.cloud.gateway.default-filters`,该属性可以接收一个filter列表。如下定义了一系列默认filter: +```yml +spring: + cloud: + gateway: + default-filters: + - AddResponseHeader=X-Response-Default-Red, Default-Blue + - PrefixPath=/httpbin +``` +## Global Filters +GlobalFilter接口的签名和Gateway接口的签名一样。GlobalFilter会在满足条件后应用于所有的routes。 +### 组合Global Filter和Gateway Filter +当请求匹配到一个route之后,filtering web handler将所有的GlobalFilter实例和route对应的Gateway Filter实例添加到一个filter chain中。该filter chain通过`org.springframework.core.Ordered`接口进行排序。filter chain中排序最靠前的filter在pre-phase中位于第一个,并且在post-phase中位于最后一个。 +如下配置了一个filter chain: +```java +@Bean +public GlobalFilter customFilter() { + return new CustomGlobalFilter(); +} + +public class CustomGlobalFilter implements GlobalFilter, Ordered { + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + log.info("custom global filter"); + return chain.filter(exchange); + } + + @Override + public int getOrder() { + return -1; + } +} +``` \ No newline at end of file