Spring Cloud Gateway
- 一、网关的概念
- 二、Route
- 简介
- Route Predicate Factories
- The After Route Predicate Factory
- The Before Route Predicate Factory
- The Between Route Predicate Factory
- The Header Route Predicate Factory
- The Host Route Predicate Factory
- The Method Route Predicate Factory
- The Path Route Predicate Factory
- The Query Route Predicate Factory
- The RemoteAddr Route Predicate Factory
- The Weight Route Predicate Factory
- yaml文件predicts、filters2种写法
- 三、GatewayFilter工厂簇
- The AddRequestHeader GatewayFilter Factory
- The AddRequestParameter GatewayFilter Factory
- The AddResponseHeader GatewayFilter Factory
- The DedupeResponseHeader GatewayFilter Factory
- The Hystrix GatewayFilter Factory
- The FallbackHeaders GatewayFilter Factory
- The MapRequestHeader GatewayFilter Factory
- The PrefixPath GatewayFilter Factory
- The PreserveHostHeader GatewayFilter Factory
- The RequestRateLimiter GatewayFilter Factory
- The Redis RateLimiter
- The RedirectTo GatewayFilter Factory
- The RemoveRequestHeader GatewayFilter Factory
- RemoveResponseHeader GatewayFilter Factory
- The RemoveRequestParameter GatewayFilter Factory
- The RewritePath GatewayFilter Factory
- RewriteLocationResponseHeader GatewayFilter Factory
- The RewriteResponseHeader GatewayFilter Factory
- The SaveSession GatewayFilter Factory
- The SecureHeaders GatewayFilter Factory
- The SetPath GatewayFilter Factory
- The SetRequestHeader GatewayFilter Factory
- The SetResponseHeader GatewayFilter Factory
- The SetStatus GatewayFilter Factory
- The StripPrefix GatewayFilter Factory
- The Retry GatewayFilter Factory
- The RequestSize GatewayFilter Factory
- Modify a Request Body GatewayFilter Factory
- Modify a Response Body GatewayFilter Factory
- Default Filters
- 四、GlobalFilters工厂簇
- 组合GlobalFilter和 GatewayFilter顺序
- Forward Routing Filter
- The LoadBalancerClientFilter
- ReactiveLoadBalancerClientFilter
- The Netty Routing Filter
- The Netty Write Response Filter
- The RouteToRequestUrl Filter
- The Websocket Routing Filter
- 网关Metrics监控
- 五、HttpHeadersFilters
- 七、Route元数据配置
- 八、Http超时设置
- 九、问题定位
- 十、开发指南
- 十一、踩坑记录
最近在看项目中的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
如果请求方法是GET或POST,则此路由匹配
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工厂接受fromHeader
和toHeader
参数。它创建一个新的命名头(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 , 所以在原请求路径不包含版本时,将版本剥离删除。
步骤:
- api.example.com/some/object/name
- api.example.com/v2/some/object/id
- 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
ForwardRoutingFilter
在exchange
属性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_ATTR
的exchange
属性中查找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_ATTR
的exchange
属性中查找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
具有ws
或wss
方案,则运行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类下的接口】