Spring Cloud Gateway—网关
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Cloud Gateway—网关相关的知识,希望对你有一定的参考价值。
7. 全局过滤器
该接口具有与 相同的签名。 这些是有条件地应用于所有路由的特殊过滤器。GlobalFilter
GatewayFilter
此接口及其用法可能会在未来的里程碑版本中发生变化。 |
7.1. 全局过滤器和网关过滤器的组合排序
当请求与路由匹配时,筛选 Web 处理程序会将 的所有实例和所有特定于路由的实例添加到筛选器链中。 此组合筛选器链按接口排序,您可以通过实现方法进行设置。GlobalFilter
GatewayFilter
org.springframework.core.Ordered
getOrder()
由于Spring Cloud Gateway区分了过滤器逻辑执行的“前”和“后”阶段(请参阅其工作原理),因此优先级最高的过滤器是“前”阶段的第一个和“后”阶段的最后一个。
以下清单配置筛选器链:
例 59。示例配置.java
@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;
7.2. 转发路由过滤器
在交换属性中查找 URI。 如果 URL 有 ascheme(例如),它使用 Springto 处理请求。 请求 URL 的路径部分将被转发 URL 中的路径覆盖。 未修改的原始 URL 将追加到属性中的列表中。ForwardRoutingFilter
ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
forward
forward:///localendpoint
DispatcherHandler
ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
7.3.反应式负载均衡器客户端过滤器
在名为的交换属性中查找 URI。 如果 URL 具有方案(例如),它将使用春云将名称(在本例中)解析为实际主机和端口,并替换同一属性中的 URI。 未修改的原始 URL 将追加到属性中的列表中。 筛选器还会在属性中查找它是否相等。 如果是这样,则适用相同的规则。 以下清单配置:ReactiveLoadBalancerClientFilter
ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
lb
lb://myservice
ReactorLoadBalancer
myservice
ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
lb
ReactiveLoadBalancerClientFilter
例 60.应用程序.yml
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**
默认情况下,当找不到服务实例时,返回 ais 值。 您可以将网关配置为返回 aby 设置。 |
从覆盖中转出的价值 向网关发出的请求中指定的方案。 例如,如果请求进入网关但表明它不安全,则下游请求将被发出。 相反的情况也可以适用。 但是,在网关配置中为路由指定了 ifis,前缀将被去除,并且路由 URL 生成的方案将覆盖配置。 |
网关支持所有负载均衡器功能。您可以在Spring Cloud Commons文档中阅读有关它们的更多信息。 |
7.4. 网络路由过滤器
如果位于交换属性中的 URL 具有主动脉方案,则 Netty 路由过滤器将运行。 它使用 Nettyto 发出下游代理请求。 响应放在 exchange 属性中,以便在以后的筛选器中使用。 (还有一个实验性执行相同的功能,但不需要Netty。ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
http
https
HttpClient
ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR
WebClientHttpRoutingFilter
7.5. 网络写入响应过滤器
如果存在 Nettyin 交换属性,则运行。 它在所有其他筛选器完成后运行,并将代理响应写回网关客户端响应。 (还有一个实验性执行相同的功能,但不需要Netty。NettyWriteResponseFilter
HttpClientResponse
ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR
WebClientWriteResponseFilter
7.6.路由到请求网址过滤器
如果交换属性中有对象,则为theruns。 它基于请求 URI 创建一个新的 URI,但使用对象的 URI 属性进行更新。 新的 URI 放置在交换属性中。Route
ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR
RouteToRequestUrlFilter
Route
ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
如果 URI 具有方案前缀,例如,该方案将从 URI 中剥离并放置在 中以供稍后在筛选器链中使用。lb:ws://serviceid
lb
ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
7.7. Websocket 路由过滤器
如果位于交换属性中的 URL 具有主动脉方案,则运行 websocket 路由过滤器。它使用 Spring WebSocket 基础架构将 websocket 请求转发到下游。ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
ws
wss
您可以通过在 URI 前面加上前缀来对 websocket 进行负载平衡,例如。lb
lb:ws://serviceid
如果使用SockJS作为普通 HTTP 的回退,则应配置正常的 HTTP 路由以及 websocket 路由。 |
以下清单配置 websocket 路由筛选器:
例 61.应用程序.yml
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/**
7.8. 网关指标过滤器
要启用网关指标,请将 spring-boot-starter-actuator 添加为项目依赖项。然后,默认情况下,只要属性未设置为 ,网关指标筛选器就会运行。此筛选器添加使用以下标记命名的计时器指标:spring.cloud.gateway.metrics.enabled
false
spring.cloud.gateway.requests
-
routeId
:路由 ID。 -
routeUri
:API 路由到的 URI。 -
outcome
:结果,按HttpStatus.Series 分类。 -
status
:返回给客户端的请求的 HTTP 状态。 -
httpStatusCode
:返回到客户端的请求的 HTTP 状态。 -
httpMethod
:用于请求的 HTTP 方法。
此外,通过属性(默认情况下设置为 false),您可以使用标签激活额外的指标:spring.cloud.gateway.metrics.tags.path.enabled
-
path
:请求的路径。
然后,可以从中抓取这些指标,并且可以轻松地与Prometheus集成以创建Grafana仪表板。/actuator/metrics/spring.cloud.gateway.requests
要启用普罗米修斯端点,请添加项目依赖项。 |
7.9. 将交易所标记为路由
网关路由后,它会通过添加到交换属性来将该交换标记为“已路由”。将请求标记为已路由后,其他路由筛选器将不会再次路由该请求, 基本上跳过过滤器。您可以使用一些方便的方法将交易所标记为路由 或检查交换是否已路由。ServerWebExchange
gatewayAlreadyRouted
-
ServerWebExchangeUtils.isAlreadyRouted
获取对象并检查它是否已被“路由”。ServerWebExchange
-
ServerWebExchangeUtils.setAlreadyRouted
获取对象并将其标记为“路由”。ServerWebExchange
8. HttpHeadersFilters
HttpHeadersFilters在将请求发送到下游之前应用于请求,例如在。NettyRoutingFilter
8.1. 转发标头过滤器
标头筛选器创建要发送到下游服务的标头。它将当前请求的标头、方案和端口添加到任何现有的标头中。Forwarded
Forwarded
Host
Forwarded
8.2. 删除跳跃跳头过滤器
标头筛选器从转发的请求中删除标头。删除的默认标头列表来自IETF。RemoveHopByHop
默认删除的标头为:
- 连接
- 保持活力
- 代理身份验证
- 代理授权
- 泰
- 拖车
- 传输编码
- 升级
若要更改此设置,请将属性设置为要删除的标头名称列表。spring.cloud.gateway.filter.remove-hop-by-hop.headers
8.3. 外部标头过滤器
标头筛选器创建各种转发器以发送到下游服务。它使用当前请求的标头,方案,端口和路径来创建各种标头。XForwarded
X-Forwarded-*
Host
单个标头的创建可以通过以下布尔属性(默认为 true)控制:
-
spring.cloud.gateway.x-forwarded.for-enabled
-
spring.cloud.gateway.x-forwarded.host-enabled
-
spring.cloud.gateway.x-forwarded.port-enabled
-
spring.cloud.gateway.x-forwarded.proto-enabled
-
spring.cloud.gateway.x-forwarded.prefix-enabled
附加多个标头可以通过以下布尔属性(默认为 true)控制:
-
spring.cloud.gateway.x-forwarded.for-append
-
spring.cloud.gateway.x-forwarded.host-append
-
spring.cloud.gateway.x-forwarded.port-append
-
spring.cloud.gateway.x-forwarded.proto-append
-
spring.cloud.gateway.x-forwarded.prefix-append
9. TLS 和 SSL
网关可以按照通常的 Spring 服务器配置侦听 HTTPS 上的请求。 以下示例演示如何执行此操作:
例 62.应用程序.yml
server:
ssl:
enabled: true
key-alias: scg
key-store-password: scg1234
key-store: classpath:scg-keystore.p12
key-store-type: PKCS12
您可以将网关路由路由到 HTTP 和 HTTPS 后端。 如果要路由到 HTTPS 后端,则可以使用以下配置将网关配置为信任所有下游证书:
例 63.应用程序.yml
spring:
cloud:
gateway:
httpclient:
ssl:
useInsecureTrustManager: true
使用不安全的信任管理器不适合生产。 对于生产部署,您可以使用一组已知证书配置网关,这些证书可以通过以下配置信任这些证书:
例 64.应用程序.yml
spring:
cloud:
gateway:
httpclient:
ssl:
trustedX509Certificates:
- cert1.pem
- cert2.pem
如果 Spring 云网关未配置受信任的证书,则使用默认的信任存储(您可以通过设置系统属性来覆盖该信任存储)。javax.net.ssl.trustStore
9.1. TLS 握手
网关维护用于路由到后端的客户端池。 通过 HTTPS 进行通信时,客户端会启动 TLS 握手。 许多超时与此握手相关联。 您可以配置这些超时,可以按如下方式配置(显示默认值):
例 65.应用程序.yml
spring:
cloud:
gateway:
httpclient:
ssl:
handshake-timeout-millis: 10000
close-notify-flush-timeout-millis: 3000
close-notify-read-timeout-millis: 0
10. 配置
Spring Cloud Gateway 的配置由一组实例驱动。 以下清单显示了接口的定义:RouteDefinitionLocator
RouteDefinitionLocator
例 66。路由定义定位器.java
public interface RouteDefinitionLocator
Flux<RouteDefinition> getRouteDefinitions();
默认情况下,使用 Spring Boot 的机制加载属性。PropertiesRouteDefinitionLocator
@ConfigurationProperties
前面的配置示例都使用使用位置参数而不是命名参数的快捷方式表示法。 以下两个示例是等效的:
例 67.应用程序.yml
spring:
cloud:
gateway:
routes:
- id: setstatus_route
uri: https://example.org
filters:
- name: SetStatus
args:
status: 401
- id: setstatusshortcut_route
uri: https://example.org
filters:
- SetStatus=401
对于网关的某些用法,属性是足够的,但某些生产用例受益于从外部源(如数据库)加载配置。未来的里程碑版本将具有基于Spring Data Repository的实现,例如Redis,MongoDB和Cassandra。RouteDefinitionLocator
10.1. 路由定义指标
要启用度量,请将弹簧-引导-启动器-执行器添加为项目依赖项。然后,默认情况下,只要属性设置为 ,指标就可用。将添加一个名为的仪表指标,其值是 的数量。此指标可从以下网址获得。RouteDefinition
spring.cloud.gateway.metrics.enabled
true
spring.cloud.gateway.routes.count
RouteDefinitions
/actuator/metrics/spring.cloud.gateway.routes.count
11. 路由元数据配置
您可以使用元数据为每个路由配置其他参数,如下所示:
例 68.应用程序.yml
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);
12. Http超时配置
可以为所有路由配置 http 超时(响应和连接),并为每个特定路由覆盖。
12.1. 全局超时
要配置全局 http 超时:
必须以毫秒为单位指定。
必须指定为 java.time.Durationconnect-timeout
response-timeout
全局 HTTP 超时示例
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
12.2. 每路由超时
要配置每个路由超时:
必须以毫秒为单位指定。
必须以毫秒为单位指定。connect-timeout
response-timeout
通过配置进行按路由 HTTP 超时配置
- id: per_route_timeouts
uri: https://example.org
predicates:
- name: Path
args:
pattern: /delay/timeout
metadata:
response-timeout: 200
connect-timeout: 200
使用 Java DSL 的每路由超时配置
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();
具有负值的每个路由将禁用全局值。response-timeout
response-timeout
- id: per_route_timeouts
uri: https://example.org
predicates:
- name: Path
args:
pattern: /delay/timeout
metadata:
response-timeout: -1
12.3. 流畅的Java路由API
为了允许在Java中进行简单的配置,thebean包含一个流畅的API。 以下清单显示了它的工作原理:RouteLocatorBuilder
例 69。网关示例应用程序.java
// 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();
此样式还允许使用更多自定义谓词断言。 由 bebean 定义的谓词使用逻辑进行组合。 通过使用流畅的Java API,您可以在类上使用,和运算符。RouteDefinitionLocator
and
and()
or()
negate()
Predicate
12.4.发现客户端路由定义定位器
您可以将网关配置为基于在兼容服务注册表中注册的服务创建路由。DiscoveryClient
要启用此功能,请设置并确保实现(例如 Netflix Eureka、Consul 或 Zookeeper)位于类路径上并启用。spring.cloud.gateway.discovery.locator.enabled=true
DiscoveryClient
12.4.1. 为Discovery客户端路由配置谓词和过滤器
默认情况下,网关定义单个谓词,并为使用 a 创建的路由进行筛选。DiscoveryClient
默认谓词是用模式定义的路径谓词,其中 来自 的服务的 ID。/serviceId/**
serviceId
DiscoveryClient
默认过滤器是带有正则表达式和替换的重写路径过滤器。 这会在向下游发送请求之前从路径中剥离服务 ID。/serviceId/?(?<remaining>.*)
/$remaining
如果要自定义路由使用的谓词或筛选器,setand。 执行此操作时,如果要保留该功能,则需要确保包含前面显示的默认谓词和筛选器。 以下示例显示了它的外观:DiscoveryClient
spring.cloud.gateway.discovery.locator.predicates[x]
spring.cloud.gateway.discovery.locator.filters[y]
例 70。应用程序属性
spring.cloud.gateway.discovery.locator.predicates[0].name: Path
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "/+serviceId+/**"
spring.cloud.gateway.discovery.locator.predicates[1].name: Host
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "**.foo.com"
spring.cloud.gateway.discovery.locator.filters[0].name: CircuitBreaker
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "/ + serviceId + /?(?<remaining>.*)"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "/$remaining"
13. 反应堆网络访问日志
要启用 Reactor Netty 访问日志,请设置。-Dreactor.netty.http.server.accessLogEnabled=true
它必须是 Java 系统属性,而不是 Spring Boot 属性。 |
您可以将日志记录系统配置为具有单独的访问日志文件。以下示例创建回日志配置:
例 71。登录.xml
<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
<file>access_log.log</file>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="accessLog" />
</appender>
<logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
<appender-ref ref="async"/>
</logger>
14. CORS 配置
您可以配置网关以控制 CORS 行为。“全局”CORS 配置是Spring FrameworkCorsConfiguration 的 URL 模式映射。 以下示例配置 CORS:
例 72.应用程序.yml
spring:
cloud:
gateway:
globalcors:
cors-configurations:
[/**]:
allowedOrigins: "https://docs.spring.io"
allowedMethods:
- GET
在前面的示例中,允许来自所有 GET 请求路径的请求发出 CORS 请求。docs.spring.io
若要为某些网关路由谓词未处理的请求提供相同的 CORS 配置,请将属性设置为 。 当您尝试支持 CORS 预检请求并且您的路由谓词未计算 to(因为 HTTP 方法)时,这很有用。spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping
true
true
options
15. 执行器接口
执行器端点允许您监控 Spring 云网关应用程序并与之交互。 若要远程访问终结点,必须在应用程序属性中启用并通过HTTP 或 JMX 公开终结点。 以下清单显示了如何执行此操作:/gateway
例 73。应用程序属性
management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway
15.1. 详细执行器格式
Spring Cloud Gateway中添加了一种新的,更详细的格式。 它为每个路由添加了更多详细信息,使您可以查看与每个路由关联的谓词和筛选器以及任何可用的配置。 以下示例配置:/actuator/gateway/routes
[
"predicate": "(Hosts: [**.addrequestheader.org] && Paths: [/headers], match trailing slash: true)",
"route_id": "add_request_header_test",
"filters": [
"[[AddResponseHeader X-Response-Default-Foo = Default-Bar], order = 1]",
"[[AddRequestHeader X-Request-Foo = Bar], order = 1]",
"[[PrefixPath prefix = /httpbin], order = 2]"
],
"uri": "lb://testservice",
"order": 0
]
默认情况下启用此功能。若要禁用它,请设置以下属性:
例 74。应用程序属性
spring.cloud.gateway.actuator.verbose.enabled=false
这将默认为将来的版本。true
15.2. 检索路由过滤器
本节详细介绍如何检索路由筛选器,包括:
- 全局筛选器
- [网关路由过滤器]
15.2.1. 全局过滤器
要检索应用于所有路由的全局筛选器,请向 发出请求。生成的响应类似于以下内容:GET
/actuator/gateway/globalfilters
"org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5": 10100,
"org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101": 10000,
"org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@32d22650": -1,
"org.springframework.cloud.gateway.filter.ForwardRoutingFilter@106459d9": 2147483647,
"org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd5e0": 2147483647,
"org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71d23": 0,
"org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea": 2147483637,
"org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889": 2147483646
响应包含已部署的全局筛选器的详细信息。 对于每个全局筛选器,筛选器对象(例如,)都有一个字符串表示形式,以及筛选器链中的相应顺序。org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5
15.2.2. 路由过滤器
若要检索应用于路由的网关筛选器工厂,请向 发出请求。 生成的响应类似于以下内容:GET
/actuator/gateway/routefilters
"[AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
"[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]": null,
"[SaveSessionGatewayFilterFactory@4449b273 configClass = Object]": null
响应包含应用于任何特定路由的工厂的详细信息。 对于每个工厂,都有相应对象的字符串表示形式(例如,)。 请注意,该值是由于终结点控制器的实现不完整,因为它尝试设置对象在筛选器链中的顺序,这不适用于 afactory 对象。GatewayFilter
[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]
null
GatewayFilter
15.3. 刷新路由缓存
要清除路由缓存,请向 发出请求。 请求返回不带响应正文的 200。POST
/actuator/gateway/refresh
15.4. 检索网关中定义的路由
要检索网关中定义的路由,请向 发出请求。 生成的响应类似于以下内容:GET
/actuator/gateway/routes
[
"route_id": "first_route",
"route_object":
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@1e9d7e7d",
"filters": [
"OrderedGatewayFilterdelegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/674480275@6631ef72, order=0"
]
,
"order": 0
,
"route_id": "second_route",
"route_object":
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298",
"filters": []
,
"order": 0
]
响应包含网关中定义的所有路由的详细信息。 下表描述了响应的每个元素(每个元素都是一个路由)的结构:
路径 | 类型 | 描述 |
| 字符串 | 路由 ID。 |
| 对象 | 路由谓词。 |
| 数组 | 应用于路由的网关筛选器工厂。 |
| 数 | 路由顺序。 |
15.5. 检索有关特定路由的信息
要检索有关单个路由的信息,请向 (例如,) 发出请求。 生成的响应类似于以下内容:GET
/actuator/gateway/routes/id
/actuator/gateway/routes/first_route
"id": "first_route",
"predicates": [
"name": "Path",
"args": "_genkey_0":"/first"
],
"filters": [],
"uri": "https://www.uri-destination.org",
"order": 0
下表描述了响应的结构:
路径 | Spring Cloud Gateway 实现Token校验
Spring Cloud Gateway + Jwt + Oauth2 实现网关的鉴权操作 Spring Security 配置:Basic Auth + Spring Cloud Gateway |