Spring Cloud Gateway
3.1.0
12. Http超时配置
可以为所有路由配置 Http 超时(响应和连接),并为每个特定路由覆盖。
12.1. 全局超时
要配置全局 http 超时:
必须以毫秒为单位指定。
必须指定为 java.time.Duration
全局 http 超时示例
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
12.2. 每条路由超时
要配置每条路由超时:
必须以毫秒为单位指定。
必须以毫秒为单位指定。
通过配置进行每条路由 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具有负值的 per-route将禁用全局response-timeout值。
- id:per_route_timeouts
网址:https://example.org
谓词:
- 名称:路径
参数:
模式:/延迟/{超时}
元数据:
响应超时:-1
12.3. 流畅的 Java 路由 API
为了允许在 Java 中进行简单配置,RouteLocatorBuilderbean 包含一个流式 API。下面的清单显示了它是如何工作的:
例 68.GatewaySampleApplication.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();
}
这种风格还允许更多的自定义断言。bean定义的断言RouteDefinitionLocator使用逻辑组合and。通过使用 fluent Java API,您可以在类上使用and()、or()和negate()运算符Predicate。
12.4. 路线DiscoveryClient定义定位器
您可以将网关配置为基于在DiscoveryClient兼容服务注册表中注册的服务创建路由。
要启用此功能,请设置spring.cloud.gateway.discovery.locator.enabled=true并确保DiscoveryClient实现(例如 Netflix Eureka、Consul 或 Zookeeper)在类路径上并启用。
12.4.1. DiscoveryClient为路由配置谓词和过滤器
默认情况下,网关为使用DiscoveryClient.
默认谓词是使用模式定义的路径谓词/serviceId/**,其中serviceId是来自DiscoveryClient.
默认过滤器是带有正则表达式/serviceId/?(?.*)和替换的重写路径过滤器/${remaining}。这会在请求被发送到下游之前从路径中去除服务 ID。
如果要自定义DiscoveryClient路由使用的谓词或过滤器,请设置spring.cloud.gateway.discovery.locator.predicates[x]和spring.cloud.gateway.discovery.locator.filters[y]。这样做时,如果要保留该功能,则需要确保包含前面显示的默认谓词和过滤器。以下示例显示了它的外观:
示例 69.application.properties
spring.cloud.gateway.discovery.locator.predicates[0].name:路径
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
spring.cloud.gateway.discovery.locator.predicates[1].name:主机
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
spring.cloud.gateway.discovery.locator.filters[0].name:断路器
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
spring.cloud.gateway.discovery.locator.filters[1].name:重写路径
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/?(?<remaining>.*)'"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
13. Reactor Netty 访问日志
要启用 Reactor Netty 访问日志,请设置-Dreactor.netty.http.server.accessLogEnabled=true.
它必须是 Java 系统属性,而不是 Spring Boot 属性。
您可以将日志记录系统配置为具有单独的访问日志文件。以下示例创建一个 Logback 配置:
例 70.logback.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 配置是 URL 模式到Spring FrameworkCorsConfiguration的映射。以下示例配置 CORS:
例 71.application.yml
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "https://docs.spring.io"
allowedMethods:
- GET
在前面的示例中,允许来自docs.spring.io所有 GET 请求路径的请求的 CORS 请求。
要为某些网关路由谓词未处理的请求提供相同的 CORS 配置,请将spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping属性设置为true. 当您尝试支持 CORS 预检请求并且您的路由谓词未评估为时,这很有用,true因为 HTTP 方法是options.
15.执行器 API
执行/gateway器端点允许您监视 Spring Cloud Gateway 应用程序并与之交互。要远程访问,必须在应用程序属性中启用并通过 HTTP 或 JMX 公开端点。以下清单显示了如何执行此操作:
示例 72.application.properties
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
}
]
默认情况下启用此功能。要禁用它,请设置以下属性:
示例 73.application.properties
spring.cloud.gateway.actuator.verbose.enabled=false
这将true在未来的版本中默认使用。
15.2. 检索路由过滤器
本节详细介绍如何检索路由过滤器,包括:
- 全局过滤器
- [网关路由过滤器]
15.2.1. 全局过滤器
要检索应用于所有路由的全局过滤器GET,请向/actuator/gateway/globalfilters. 生成的响应类似于以下内容:
{
“org.spring framework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5 ”:10100,
“o rg.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101 ”:10000,
“或g.springframework.cloud.gateway.filter.NettyWriteResponseFilter@32d22650 ”:-1,
" org.springframework.cloud.gateway.filter.ForwardRoutingFilter@10 6459d9": 2147483647,
“ org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd 5e0”:2147483647,
" org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71 d23": 0,
“org.s pringframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea ”:2147483637,
“ org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889 ”:2147483646
}
响应包含已到位的全局过滤器的详细信息。对于每个全局过滤器,都有过滤器对象的字符串表示形式(例如,org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5)和过滤器链中的相应顺序。}
15.2.2. 路由过滤器
要检索应用于路由的GatewayFilter工厂GET,请向/actuator/gateway/routefilters. 生成的响应类似于以下内容:
{
“[ AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]”:空,
“[ SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]”:空,
“[ SaveSessionGatewayFilterFactory@4449b273 configClass = Object]”:空
}
响应包含GatewayFilter应用于任何特定路由的工厂的详细信息。对于每个工厂,都有对应对象的字符串表示形式(例如,[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object])。请注意,该null值是由于端点控制器的实现不完整,因为它试图设置对象在过滤器链中的顺序,这不适用于GatewayFilter工厂对象。
15.3. 刷新路由缓存
要清除路由缓存,POST请向/actuator/gateway/refresh. 该请求返回没有响应正文的 200。
15.4. 检索网关中定义的路由
要检索网关中定义的路由,GET请向/actuator/gateway/routes. 生成的响应类似于以下内容:
[{
"route_id": "first_route",
“路由对象”:{“谓词
”:“org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@1e9d7e7d ”,
“过滤器”:[
“OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/674480275@6631ef72 , order =0}”
]
},
“订单”:0
},
{
"route_id": "second_route",
“路由对象”:{“谓词
”:“org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298 ”,
“过滤器”:[]
},
“订单”:0
}]
响应包含网关中定义的所有路由的详细信息。下表描述了响应的每个元素(每个元素都是一个路由)的结构:
路径 | 类型 | 描述 |
route_id | String | 路径Id |
route_object.predicate | Object | 断言 |
route_object.filters | Array | 路由过滤器 |
order | Number | 序号 |
15.5。检索有关特定路线的信息
要检索有关单个路由的信息,GET请向/actuator/gateway/routes/{id}(例如,/actuator/gateway/routes/first_route)发出请求。生成的响应类似于以下内容:
{
"id": "first_route",
“谓词”:[{
“名称”:“路径”,
"args": {"_genkey_0":"/first"}
}],
“过滤器”:[],
"uri": "https://www.uri-destination.org",
“订单”:0
}
下表描述了响应的结构:
路径 | 类型 | 描述 |
id | String | 路径Id |
predicates | Array | 断言数组 |
filters | Array | 路由过滤器 |
uri | String | uri |
order | Number | 序号 |
15.6.创建和删除特定路线
要创建路由,请使用指定路由字段的 JSON 正文POST发出请求(请参阅检索有关特定路由的信息)。/gateway/routes/{id_route_to_create}
要删除路线,DELETE请向/gateway/routes/{id_route_to_delete}.
15.7. 回顾:所有端点的列表
下表总结了 Spring Cloud Gateway 执行器端点(请注意,每个端点都有/actuator/gateway作为基本路径):
id | 方法 | 描述 |
globalfilters | GET | 显示应用于路由的全局过滤器列表。 |
routefilters | GET | GatewayFilter列表 |
refresh | POST | 清除路由缓存。 |
routes | GET | 显示网关中定义的路由列表。 |
routes/{id} | GET | 显示有关特定路线的信息。 |
routes/{id} | GET | 向网关添加新路由。 |
routes/{id} | DELETE | 从网关中删除现有路由。 |
15.8. 在多个网关实例之间共享路由
Spring Cloud Gateway 提供了两种RouteDefinitionRepository实现。第一个是 InMemoryRouteDefinitionRepository只存在于一个网关实例的内存中。这种类型的存储库不适合跨多个网关实例填充路由。
为了在 Spring Cloud Gateway 实例的集群中共享路由,RedisRouteDefinitionRepository可以使用。要启用这种存储库,必须将以下属性设置为 true:spring.cloud.gateway.redis-route-definition-repository.enabled 与 RedisRateLimiter Filter Factory 类似,它需要使用 spring-boot-starter-data-redis-reactive Spring Boot 启动器。
16. 故障排除
本节介绍使用 Spring Cloud Gateway 时可能出现的常见问题。
16.1. 日志级别
以下记录器可能在DEBUG和TRACE级别包含有价值的故障排除信息:
- org.springframework.cloud.gateway
- org.springframework.http.server.reactive
- org.springframework.web.reactive
- org.springframework.boot.autoconfigure.web
- reactor.netty
- redisratelimiter
16.2. 窃听
Reactor NettyHttpClient可以HttpServer启用窃听。与将reactor.netty日志级别设置为DEBUG或结合使用时TRACE,它可以记录信息,例如通过网络发送和接收的标头和正文。要启用窃听,请分别为和设置spring.cloud.gateway.httpserver.wiretap=true或。spring.cloud.gateway.httpclient.wiretap=trueHttpServerHttpClient
17. 开发者指南
这些是编写网关的一些自定义组件的基本指南。
17.1. 编写自定义路由谓词工厂
为了编写路由谓词,您需要将其实现RoutePredicateFactory为 bean。有一个AbstractRoutePredicateFactory可以扩展的抽象类。
MyRoutePredicateFactory.java
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.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
}
}
17.2. 编写自定义 GatewayFilter 工厂
要编写GatewayFilter,您必须将其实现GatewayFilterFactory为 bean。您可以扩展一个名为AbstractGatewayFilterFactory. 以下示例显示了如何执行此操作:
示例 74. PreGatewayFilterFactory.java
@Component
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(builder.build()).build());
};
}
public static class Config {
//Put the configuration properties for your filter here
}
}
PostGatewayFilterFactory.java
@Component
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
}
}
17.2.1. 在配置中命名自定义过滤器和引用
自定义过滤器类名应以GatewayFilterFactory.
例如,要引用Something配置文件中命名的过滤器,该过滤器必须位于名为SomethingGatewayFilterFactory.
可以创建一个不带 GatewayFilterFactory后缀的网关过滤器,例如class AnotherThing. 此过滤器可以AnotherThing在配置文件中引用。这不是受支持的命名约定,并且在将来的版本中可能会删除此语法。请更新过滤器名称以使其符合要求。
17.3. 编写自定义全局过滤器
要编写自定义全局过滤器,您必须GlobalFilter将接口实现为 bean。这会将过滤器应用于所有请求。
以下示例分别显示了如何设置全局前置和后置过滤器:
@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();
}
18. 使用 Spring MVC 或 Webflux 构建简单网关
下面描述了另一种风格的网关。先前的文档均不适用于以下内容。
Spring Cloud Gateway 提供了一个名为ProxyExchange. 您可以在常规 Spring Web 处理程序中将其用作方法参数。它通过镜像 HTTP 动词的方法支持基本的下游 HTTP 交换。使用 MVC,它还支持通过forward()方法转发到本地处理程序。要使用ProxyExchange,请在类路径中包含正确的模块(spring-cloud-gateway-mvc或spring-cloud-gateway-webflux)。
以下 MVC 示例将请求代理到/test下游到远程服务器:
@RestController
@SpringBootApplication
public class GatewaySampleApplication {
@Value("${remote.home}")
private URI home;
@GetMapping("/test")
public ResponseEntity<?> proxy(ProxyExchange<byte[]> proxy) throws Exception {
return proxy.uri(home.toString() + "/image/png").get();
}
}
以下示例对 Webflux 执行相同的操作:
@RestController
@SpringBootApplication
public class GatewaySampleApplication {
@Value("${remote.home}")
private URI home;
@GetMapping("/test")
public Mono<ResponseEntity<?>> proxy(ProxyExchange<byte[]> proxy) throws Exception {
return proxy.uri(home.toString() + "/image/png").get();
}
}
上的便捷方法ProxyExchange使处理程序方法能够发现和增强传入请求的 URI 路径。例如,您可能希望提取路径的尾随元素以将它们传递到下游:
@GetMapping("/proxy/path/**")
public ResponseEntity<?> proxyPath(ProxyExchange<byte[]> proxy) throws Exception {
String path = proxy.path("/proxy/path/");
return proxy.uri(home.toString() + "/foos/" + path).get();
}
Spring MVC 和 Webflux 的所有特性都可用于网关处理程序方法。因此,您可以注入请求标头和查询参数,例如,您可以使用映射注释中的声明来约束传入请求。有关这些功能的更多详细信息,请参阅@RequestMappingSpring MVC 中的文档。
header()您可以使用on 上的方法将标头添加到下游响应中ProxyExchange。
get()您还可以通过向方法(和其他方法)添加映射器来操作响应标头(以及响应中您喜欢的任何其他内容)。映射器是一个Function接收传入ResponseEntity并将其转换为传出的映射器。
cookie为不向下游传递的“敏感”标头(默认情况下和authorization)和“代理”(x-forwarded-*)标头提供一流的支持。
19.配置属性
要查看所有 Spring Cloud Gateway 相关配置属性的列表,请参阅附录。