版本:3.0.2
Spring Cloud Gateway基于Spring生态提供了一套API Gateway,包括:Spring 5,Spring Boot 2和Project Reactor。Spring Cloud Gateway旨在提供一个简单、有效的API路由和一系列基础功能,如:安全,监控/指标和限流。
1、引入Spring Cloud Gateway
如果需要在项目中使用Spring Cloud Gateway,只需要在项目中引入spring-cloud-starter-gateway,详情参考Spring Cloud Project page。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
如果引入了starter,但是不想启动,可以配置spring.cloud.gateway.enabled=false。
Spring Cloud Gateway是基于Spring Boot 2.x,Spring WebFlux和Project Reactor。所以许多我们熟悉的同步库(如Spring Data和Spring Security)都可能无法在Spring Cloud Gateway中使用,如果你不太熟悉这些项目,建议在使用前先行阅读并学习相关项目文档。
Spring Cloud Gateway需要基于Netty运行,无法运行于传统Servlet容器或构建为WAR包。
2、术语
-
Route(路由):网关的基本组成单位,一个路由模块包括一个ID,一个目标URI,一组Predidate(断言)和一组Filter(过滤器)。如果断言为真,则路由匹配,目标URI会被访问。
-
Predicate(断言):Java 8的Predicate(Java 8 Function Predicate),输入类型是一个Spring Framework的 ServerWebExchange 。可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。
-
Filter(过滤器):一个特殊工程构建的一组GatewayFilter实例,你可以使用它在发送下游请求之前或之后修改requests和responses。
3、如何实现
客户端向Spring Cloud Gateway发起请求,如果网关的Gateway Handler Mapping
判断请求命中路由,则将其发送到Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
4、配置Route Predicate Factories和Gateway Filter Factories
我们可以通过两种方式配置predicates和filters:快捷方式和全量方式。
4.1、快捷方式
快捷方式由 名称=参数1,参数2
组成。
application.yml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- Cookie=mycookie,mycookievalue
例子中定义了一个Cookie路由断言,这个断言包含两个参数:cookie名称和命中的值mycookievalue
4.2、全量方式
全量方式采用传统yaml的name/value配置方式。通常由一个name key和一个args key组成,args key是一组用于配置断言或过滤器的键值对。
application.yml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- name: Cookie
args:
name: mycookie
regexp: mycookievalue
参数意义和上面的例子一致。
5、路由断言规则
Spring Cloud Gateway通过Spring WebFlux的HandlerMapping实现路由判断,Spring Cloud Gateway内建一系列路由断言规则。这些断言规则通过不同的HTTP request属性条件匹配不同路由。
5.1、After Predicate
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
After断言包含一个参数datetime,格式为ZonedDateTime,匹配所有指定时间后的请求,
5.2、Before Predicate
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
Before断言包含一个参数datetime,格式为ZonedDateTime,匹配所有指定时间前的请求
5.3、Between Predicate
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]
Between断言包含两个参数:datetime1和datetime2,格式为ZonedDateTime,匹配所有发生在两个时间之间的请求。
5.4、Cookie Predicate
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
Cookie包含两个参数,name(cookie名字)和regexp(正则表达式),匹配指定名称满足正则表达式的cookies。
5.5、Header Predicate
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
Header包含两个参数,name(header名称)和regexp(正则表达式),匹配指定名称满足正则表达式的headers。
5.6、Host Predicate
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org
Host包含一个参数,一组Host域名,匹配满足域名规则的请求。
5.7、Method Predicate
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
Method匹配HTTP methods请求方式,参数可以包含一个或多个请求方式。
5.8、Path Predicate
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}
Path包含两个参数,一组路由匹配器(PathMatcher)和一个可选的/匹配表示(matchTrailingSlash),默认是true。如果matchTrailingSlash为false,则/red/1/
将匹配失败。
5.9、Query Predicate
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.
Query包含两个参数,一个请求参数param和一个可选正则表达式regexp,匹配指定名称的满足正则表达式的请求参数。
5.10、RemoteAddr Predicate
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24
RemoteAddr包含一个IPv4或IPv6的字符串列表,例如192.168.0.1/16,配置包含在列表内的请求。
5.11、Weight Predicate
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
Weight包含两个参数,group和weight(int类型),将根据分组权重分配路由请求,如例子中80%导流到weighthigh.org,20%导流到weightlow.org
6、过滤器
路由过滤器用于修改HTTP request和HTTP response,Spring Cloud Gateway包含许多内建过滤器。
6.1、AddRequestHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
AddRequestHeader包含name和value两个参数,可添加参数(如X-Request-red:blue)到所有匹配的下游请求头。AddRequestHeader还可以匹配URI请求参数,并在value中使用,例如:
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
predicates:
- Path=/red/{segment}
filters:
- AddRequestHeader=X-Request-Red, Blue-{segment}
6.2、AddRequestParameter GatewayFilter
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=red, blue
AddRequestParameter包含name和value两个参数,可添加参数(如red-blue)到所有匹配的请求参数。AddRequestParameter还可以匹配URI参数,并用于value中,例如:
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- AddRequestParameter=foo, bar-{segment}
6.3、AddResponseHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
filters:
- AddResponseHeader=X-Response-Red, Blue
AddResponseHeader包含name和value两个参数,可添加参数到下游response的headers中,如X-Response-Foo:Bar。AddResponseHeader还可以匹配URI请求参数,并用于value中,例如:
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- AddResponseHeader=foo, bar-{segment}
6.4、DedupeResponseHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: dedupe_response_header_route
uri: https://example.org
filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
DedupeResponseHeader包含一个name(一个通过空格分隔的header名称列表)和一个可选的strategy(默认RETAIN_FIRST-保留优先,RETAIN_LAST和RETAIN_UNIQUE)。例如删除Response Header中Access-Control-Allow-Credentials和Access-Control-Allow-Origin重复的值。
6.5、CircuitBreaker GatewayFilter
CircuitBreaker GatewayFilter基于Spring Cloud的CircuitBreaker实现,支持各种熔断限流实现,例如Resilience4J,如果要使用CircuitBreaker GatewayFilter需引入依赖如spring-cloud-starter-circuitbreaker-reactor-resilience4j。
spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingServiceEndpoint
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/inCaseOfFailureUseThis
- RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint
6.6、FallbackHeader GatewayFilter
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
FallbackHeaders可用于添加异常详情并传递到fallbackUri中。例如,当发生熔断异常时,请求将重定向到
localhost:9994,并添加Execution-Exception-Type到请求Header中。
常用参数如下:
-
executionExceptionTypeHeaderName ("Execution-Exception-Type")
-
executionExceptionMessageHeaderName ("Execution-Exception-Message")
-
rootCauseExceptionTypeHeaderName ("Root-Cause-Exception-Type")
-
rootCauseExceptionMessageHeaderName ("Root-Cause-Exception-Message")
详情请参考 Spring Cloud CircuitBreaker Factory section.
6.7、MapRequestHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: map_request_header_route
uri: https://example.org
filters:
- MapRequestHeader=Blue, X-Request-Red
MapRequestHeader包含fromHeader和toHeader两个参数,将自动匹配HTTP请求中是否包含fromHeader(如Blue),如不存在,则不影响,如存在,则替换fromHeader为toHeader(如替换Blue为X-Request-Red)。
6.8、PrefixPath GatewayFilter
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- PrefixPath=/mypath
PrefixPath包含单个prefix参数,将为所有满足条件的请求添加前缀,例如请求/hello将变为/mypath/hello
6.9、PreserveHostHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: preserve_host_route
uri: https://example.org
filters:
- PreserveHostHeader
PreserveHostHeader没有参数,定义了原始Host将一定被传输到下游请求。
6.10、RequestRateLimiter GatewayFilter
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
rate-limiter: "#{@myRateLimiter}"
key-resolver: "#{@userKeyResolver}"
RequestRateLimiter使用限流器(RateLimiter)实现请求限流,这个过滤器包含一个可选的的keyResolver,KeyResolver接口采用可插拔策略实现限制请求的密钥获取,默认实现是PrincipalNameKeyResolver。
6.11、RedirectTo GatewayFilter
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- RedirectTo=302, https://acme.org
RedirectTo包含两个参数status(HTTP状态码)和url。当状态为302时,将重定向为Location:https://acme.org。
6.12、RemoveRequestHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveRequestHeader=X-Request-Foo
RemoveRequestHeader包含一个name参数,将删除指定名称的header,如X-Request-Foo Header在发送到下游之前将删除。
6.13、RemoveResponseHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: removeresponseheader_route
uri: https://example.org
filters:
- RemoveResponseHeader=X-Response-Foo
RemoveResponseHeader包含一个name参数,将删除指定名称的header,如X-Request-Foo Header在返回之前将删除。
6.14、RemoveRequestParameter GatewayFilter
spring:
cloud:
gateway:
routes:
- id: removerequestparameter_route
uri: https://example.org
filters:
- RemoveRequestParameter=red
RemoveRequestParameter包含一个name参数,将删除指定名称的请求参数,如red在发送到下游请求之前将删除。
6.15、RewritePath GatewayFilter
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: https://example.org
predicates:
- Path=/red/**
filters:
- RewritePath=/red/?(?<segment>.*), /$\{segment}
RewritePath包含一个regexp(正则表达式)和一个replacement(替代值)两个参数,用于灵活的重写请求路径。
6.16、RewriteLocationResponseHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: rewritelocationresponseheader_route
uri: http://example.org
filters:
- RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,
RewriteLoacationResponseHeader用于刘改response的Location Header,包括四个参数:
stripVersionMode:忽略版本,枚举值:NEVER_STRIP(不过滤),AS_IN_REQUEST(默认值,有时过滤),ALWAYS_STRIP(一直过滤)
locationHeaderName:header 名称
hostValue:如果提供,将替换Location中的host:port
protocolsRegex:协议名称的匹配正则表达式,如果不命中,则不执行,默认值为http|https|ftp|ftps
6.17、RewriteResponseHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: rewriteresponseheader_route
uri: https://example.org
filters:
- RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=***
RewriteResponseHeader包含三个参数:name,regexp和replacement,提供灵活的方式重写Response Header。
6.18、SaveSession GatewayFilter
spring:
cloud:
gateway:
routes:
- id: save_session
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- SaveSession
SaveSession将在转发到下游请求之前执行WebSession::save操作。
6.19、SecureHeaders GatewayFilter
SecureHeaders将添加一系列Header到response,添加的参数如下:
-
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)
6.20、SetPath GatewayFilter
spring:
cloud:
gateway:
routes:
- id: setpath_route
uri: https://example.org
predicates:
- Path=/red/{segment}
filters:
- SetPath=/{segment}
SetPath包含一个参数template,通过URI template模板来修改请求路径。例如/red/blue将自动修改为/blue
6.21、SetRequestHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: setrequestheader_route
uri: https://example.org
filters:
- SetRequestHeader=X-Request-Red, Blue
SetRequestHeader包括name和value两个参数,用于替换指定名称的header,如果存在相同名称的header(如X-Request-Red:1234),则替换为X-Request-Red:Blue。
6.22、SetResponseHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- SetResponseHeader=foo, bar-{segment}
SetResponseHeader包括name和value两个参数,用于替换指定名称的header,如果存在相同名称的header(如foo),则替换为bar-{segment}。
6.23、SetStatus GatewayFilter
spring:
cloud:
gateway:
routes:
- id: setstatusstring_route
uri: https://example.org
filters:
- SetStatus=BAD_REQUEST
- id: setstatusint_route
uri: https://example.org
filters:
- SetStatus=401
SetStatus包含单个参数status,格式为HttpStatus,如例子中Http状态被设置为401。
6.24、StripPrefix GatewayFilter
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: https://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2
StripPrefix包括一个参数parts,表示请求Path的下标。例如请求路径为/name/blue/red,则将替换为https://nameservice/red
6.25、Retry GatewayFilter
Retry包含以下参数:
-
retries: 重试次数
-
statuses: 引起重试的 HTTP status codes ,参考org.springframework.http.HttpStatus.
-
methods: 引起重试的HTTP methods,参考 org.springframework.http.HttpMethod.
-
series: 系列HTTP状态码,参考 org.springframework.http.HttpStatus.Series.
-
exceptions: 引起重试的异常列表
-
backoff: 重试配置的指数补偿.
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
6.26、RequestSize GatewayFilter
spring:
cloud:
gateway:
routes:
- id: request_size_route
uri: http://localhost:8080/upload
predicates:
- Path=/upload
filters:
- name: RequestSize
args:
maxSize: 5000000
RequestSize包含一个maxSize参数,默认单位为B,可以自定义为KB或MB,用于限制请求大小。
6.27、SetRequestHostHeader GatewayFilter
spring:
cloud:
gateway:
routes:
- id: set_request_host_header_route
uri: http://localhost:8080/headers
predicates:
- Path=/headers
filters:
- name: SetRequestHostHeader
args:
host: example.org
SetRequestHostHeader包含一个host参数,用于替换host header为指定的值。
6.28、ModifyRequestBody GatewayFilter
ModifyRequestBody用于修改请求body
@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;
}
}
6.29、ModifyResponseBody GatewayFilter
ModifyResponseBody用于修改response body
@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();
}
6.30、TokenRelay GatewayFilter
TokenRelay可以通过转发到SSO代理服务实现OAuth2校验,需要引入依赖org.springframework.boot:spring-boot-starter-oauth2-client。
App.java
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("resource", r -> r.path("/resource")
.filters(f -> f.tokenRelay())
.uri("http://localhost:9000"))
.build();
}
application.yaml
spring:
cloud:
gateway:
routes:
- id: resource
uri: http://localhost:9000
predicates:
- Path=/resource
filters:
- TokenRelay=
6.31、默认Filter
可以通过spring.cloud.gateway.default-filters的方式添加作用于全部路由的过滤器,可以设置一系列filter作为默认过滤器
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
7、Global Filters(全局过滤器)
Global Filter是一种作用于全部路由的特殊过滤器。
7.1、自定义Global Filter和排序
可以通过继承GlobalFilter接口自定义全局过滤器,Spring Cloud Gateway将自动加载所有全局过滤器构建过滤链。
过滤链条的执行顺序通过org.springframework.core.Ordered接口实现,order越大优先级越低:
@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、Forward Routing Filter
ForwardRoutingFilter判断URL是否包含forward标识(如:forward://localendpoint),将使用 DispatcherHandler去处理这请求,请求URL的路径将被转发URL中的路径覆盖。
7.3、LoadBalancerClientFilter
LoadBalancerClientFilter判断URL是否包含lb标识(如:lb://myservice),将使用Spring Cloud LoadBalancerClient去分析myservice的真实地址和端口实现负载均衡。
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**
通常情况下,如果loadbalancer没有找到对应的服务将默认返回503,如果需要返回404,请配置spring.cloud.gateway.loadbalancer.use404=true。
7.4、ReactiveLoadBalancerClientFilter
LoadBalancerClientFilter判断URL是否包含lb标识(如:lb://myservice),将使用Spring Cloud ReactorLoadBalancer去分析myservice的真实地址和端口实现负载均衡。和LoadBalancerClientFilter的区别在于是基于响应式实现。
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**
7.5、Netty Routing Filter
NettyRoutingFilter判断URL是否包含http或者https标识,将使用Netty HttpClient发起一个下游代理请求。
7.6、Netty Write Response Filter
如果存在Netty HttpClientResponse时,NettyWriteResponseFilter将在所有filter执行完成后执行并返回response给网关客户端。
7.7、RouteToRequestUrl Filter
如果存在Route对象,RouteToRequestUrlFilter将执行并创建一个基于Request请求但是根据Route对象更新的新URI。
7.8、Websocket Routing Filter
如果URI中包含ws或wss标识,Websocket routing filter将执行,实现websocket请求下游转发。
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.9、Gateway Metrics Filter
添加spring-boot-starter-actuator引用,则可以通过spring.cloud.gateway.metrics.enabled启动gateway metrics监控,默认true。可以通过/actuator/metrics/gateway.requests查看对应指标参数,通常包括以下标识:
-
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.
7.10、路由执行标识
可以通过设置ServerWebExchange的gatewayAlreadyRouted属性标识exchange对象是否被路由处理过,如果标识为routed,则其他路由过滤器将不再执行。
-
ServerWebExchangeUtils.isAlreadyRouted: takes a ServerWebExchange object and checks if it has been “routed”.
-
ServerWebExchangeUtils.setAlreadyRouted takes a ServerWebExchange object and marks it as “routed”.
8、HttpHeadersFilters
HttpHeadersFilters类似于NettyRoutingFilter,作用于所有下游请求发送之前。
8.1、Forwarded Headers Filter
Forwarded Filter创建一个Forwarded 请求头并发送到下游服务。
8.2、RemoveHopByHop Headers Filter
RemoveHopByHop用于移除前置请求的请求头,默认可移除的请求头如下:
-
Connection
-
Keep-Alive
-
Proxy-Authenticate
-
Proxy-Authorization
-
TE
-
Trailer
-
Transfer-Encoding
-
Upgrade
8.3、XForwarded Headers Filter
XForwarded Filter用于创建一系列X-Forwarded-*请求头并发送到下游服务。
通过以下属性创建当个请求头:
-
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
通过以下属性追加请求头:
-
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
网关可以通过配置支持HTTPS请求
server:
ssl:
enabled: true
key-alias: scg
key-store-password: scg1234
key-store: classpath:scg-keystore.p12
key-store-type: PKCS12
10、Configuation
Configuation是由一组RouteDefinitionLocator实例实现的。PropertiesRouteDefinitionLocator通过Spring Boot的@ConfigurationProperties机制加载配置,
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
Example application.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
11、路由元数据配置(Metadata)
我们可以通过额外的属性给每个路由配置元数据,例如:
spring:
cloud:
gateway:
routes:
- id: route_with_metadata
uri: https://example.org
metadata:
optionName: "OptionValue"
compositeObject:
name: "value"
iAmNumber: 1
12、HTTP超时配置
12.1、全局超时配置
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
12.2、单路由超时配置
- id: per_route_timeouts
uri: https://example.org
predicates:
- name: Path
args:
pattern: /delay/{timeout}
metadata:
response-timeout: 200
connect-timeout: 200
也可以通过代码配置:
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();
}
13、Netty访问日志
可以通过设置-Dreactor.netty.http.server.accessLogEnabled=true来打开Reactor Netty访问日志。注意是启动参数而不是Spring Boot配置
可以通过logback配置输出日志文件:
<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配置
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "https://docs.spring.io"
allowedMethods:
- GET
例子中,允许docs.spring.io进行跨域的get请求操作。
15、Actuator API
网关通过暴露/gateway,创建actuator endpoints来暴露HTTP或者JMX来监控和管理应用。
application.properties
management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway
提供如下actuator endpoints:
ID | HTTP Method | Description |
---|---|---|
globalfilters | GET | 查看全局路由过滤器信息 |
routefilters | GET | 查看 GatewayFilter 信息 |
refresh | POST | 刷新路由缓存 |
routes | GET | 查看路由信息 |
routes/{id} | GET | 查询指定路由信息 |
routes/{id} | POST | 新增新路由 |
routes/{id} | DELETE | 删除指定路由 |
16、故障排除
16.1 日志等级
通过调整下列package的日志等级为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 窃听(Wiretap)
可以通过开启HttpClient(spring.cloud.gateway.httpserver.wiretap=true)和HttpServer(spring.cloud.gateway.httpclient.wiretap=true)的窃听模式获取如请求头,body等日志信息。
17、开发手册
17.1、自定义Route Predicate
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
}
}
17.2、自定义GatewayFilter
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(builder.build()).build());
};
}
public static class Config {
//Put the configuration properties for your filter here
}
}
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
}
}
17.3、自定义Global Filters
@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();
}