spring cloud gateway系列教程4—其他配置

spring cloud gateway系列教程目录

  1. spring cloud gateway系列教程1—Route Predicate

  2. spring cloud gateway系列教程2——GatewayFilter_上篇

  3. spring cloud gateway系列教程2——GatewayFilter_下篇

  4. spring cloud gateway系列教程3—Global Filters

  5. spring cloud gateway系列教程4—其他配置

    1. TLS / SSL

Spring Cloud Gateway使用HTTPS,是和普通的Spring boot服务配置是一样的,比如:

application.yml.

1
2
3
4
5
6
7
server:
ssl:
enabled: true
key-alias: scg
key-store-password: scg1234
key-store: classpath:scg-keystore.p12
key-store-type: PKCS12

Spring Cloud Gateway都可以路由转给给http和HTTPS的下游后端服务,如果是路由去HTTPS后端服务,gateway像下面一样配置信任所有下游服务:

application.yml.

1
2
3
4
5
6
spring:
cloud:
gateway:
httpclient:
ssl:
useInsecureTrustManager: true

当然这种配置,线上生成环境还是不太适合的,所以gateway可以配置自己的信任的证书列表:

application.yml.

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
httpclient:
ssl:
trustedX509Certificates:
- cert1.pem
- cert2.pem

Spring Cloud Gateway如果没有配置信任证书列表,则会拿系统默认的证书库(可以通过system property的javax.net.ssl.trustStore属性来修改系统默认证书库)。

TLS Handshake

当是用HTTPS来通讯时,http客户端就需要初始化TLS握手连接了,所以就需要配置握手连接时的超时配置:

application.yml.

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
httpclient:
ssl:
handshake-timeout-millis: 10000
close-notify-flush-timeout-millis: 3000
close-notify-read-timeout-millis: 0

2. Configuration

Spring Cloud Gateway是通过一系列的RouteDefinitionLocator接口配置的,接口如下:

RouteDefinitionLocator.java.

1
2
3
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}

默认情况下,PropertiesRouteDefinitionLocator会通过Spring Boot的@ConfigurationProperties机制来加载路由配置,比如下面的例子(一个使用了完整的配置,一个使用了快捷配置,前几章也大量的用了这些配置):

application.yml.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
cloud:
gateway:
routes:
- id: setstatus_route
uri: http://example.org
filters:
- name: SetStatus
args:
status: 401
- id: setstatusshortcut_route
uri: http://www.google.com
filters:
- SetStatus=401

通常情况下,properties的配置就已经够用的了,但也有一些人的需求是从外部源来加载配置文件,比如数据库等,所以官方也承诺未来的版本会基于Spring Data Repositories实现Redis, MongoDB和Cassandra版本的RouteDefinitionLocator

2.1 Fluent Java Routes API

除了上面的配置文件配置外,也可以通过RouteLocatorBuilder的流式API来进行java实现配置。

GatewaySampleApplication.java.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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")
)
.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")
)
.build();
}

这种用法就可以通过实行Predicate<ServerWebExchange>接口来定义更复杂的匹配规则,也可以用and()or()negate()来组合不同的匹配规则,灵活性会更大一点。

2.2 DiscoveryClient Route Definition Locator

通过服务发现客户端DiscoveryClient,gateway可以基于注册了的服务自动创建路由。
只需要配置spring.cloud.gateway.discovery.locator.enabled=true,以及引入DiscoveryClient的maven依赖即可,如:Netflix Eureka, Consul or Zookeeper。

Configuring Predicates and Filters For DiscoveryClient Routes

默认情况下gateway中的GatewayDiscoveryClientAutoConfiguration以及定义了一个predicate和filter的了。
默认的predicate是配置了/serviceId/**路径的path predicate,当然serviceIdDiscoveryClient里面的服务id。
默认的filter是配置了匹配参数/serviceId/(?<remaining>.*)和替换参数/${remaining}的rewrite path filter,目的是将serviceId从path中去除掉,因为下游是不需要的。

你也可以自定义DiscoveryClient路由的predicate和filter,只需要设置spring.cloud.gateway.discovery.locator.predicates[x]spring.cloud.gateway.discovery.locator.filters[y]即可,如下:
application.properties.

1
2
3
4
5
6
7
8
9
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: Hystrix
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}'"

3. Reactor Netty Access Logs

spring cloud gateway是没有打印access log的,但是底层的Reactor Netty是有的,在应用启动命名中增加设置-Dreactor.netty.http.server.accessLogEnabled=true来开启。
注:因为Reactor Netty不是基于spring boot的,所以它并不会去spring boot的配置中获取上面的配置,所以只能在Java System Property中获取。

可以在常用的日志系统中配置日志的打印文件和格式,如logback的配置:

logback.xml.

1
2
3
4
5
6
7
8
9
10
11
12
13
<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>

4. CORS Configuration

gateway是支持CORS的配置,可以通过不同的URL规则匹配不同的CORS策略:

application.yml.

1
2
3
4
5
6
7
8
9
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "http://docs.spring.io"
allowedMethods:
- GET

有不熟悉CORS的,可以看一下这篇介绍

5. Actuator API

Spring Cloud Gateway也可以配置actuator来监控和操作一些功能点,增加下面的配置即可:

application.properties.

1
2
management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway

5.1 查看filter信息

5.1.1 Global Filters

使用GET请求gateway地址/actuator/gateway/globalfilters,就可以获取类似于下面的返回:

1
2
3
4
5
6
7
8
9
10
{
"or[email protected]77856cc5": 10100,
"o[email protected]4f6fd101": 10000,
"or[email protected]32d22650": -1,
"[email protected]6459d9": 2147483647,
"[email protected]5e0": 2147483647,
"[email protected]d23": 0,
"org.s[email protected]135064ea": 2147483637,
"[email protected]23c05889": 2147483646
}

返回信息包含了gateway的使用中的global filters实例,包含了实例的toString()order的keyvalue信息。

5.1.2 Route Filters

使用GET请求gateway地址/actuator/gateway/routefilters,就可以获取类似于下面的返回:

1
2
3
4
5
{
"[[email protected] configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
"[[email protected] configClass = Object]": null,
"[[email protected] configClass = Object]": null
}

返回信息里面包含了gateway中可以提供使用的GatewayFilter factories 详细信息,其中展示的是GatewayFilterFactory的实例toString()打印,及配置类。后面的null是某些GatewayFilter factory实现问题,本来是用来展示order的,但是GatewayFilter factory没有实现,就返回null了。

5.2 路由缓存刷新

使用POST请求gateway地址/actuator/gateway/refresh,并返回http状态码为200,标识刷新路由缓存成功。

5.3 查看路由定义信息

使用GET请求gateway地址/actuator/gateway/routes,获取类似下面的返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[{
"route_id": "first_route",
"route_object": {
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/[email protected]",
"filters": [
"OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/[email protected], order=0}"
]
},
"order": 0
},
{
"route_id": "second_route",
"route_object": {
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/[email protected]",
"filters": []
},
"order": 0
}]

上面对象的定义如下表:

key value类型 value描述
route_id String 路由id.
route_object.predicate Object Route Predicate
route_object.filters Array GatewayFilter
order Number 路由顺序
##### 5.3.1 查看单个路由信息
如果是想只获取单个路由信息,则使用GET请求地址/actuator/gateway/routes/{id}即可。
5.3.2 创建和删除路由

创建路由,使用POST请求,并附带类似下面的json body,到/gateway/routes/{id_route_to_create}即可。

1
2
3
4
5
6
7
8
{
"route_id": "second_route",
"route_object": {
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/[email protected]",
"filters": []
},
"order": 0
}

删除路由,使用DELETE请求地址/gateway/routes/{id_route_to_delete}即可。

5.4 Actuator API汇总

ID HTTP Method Description
globalfilters GET 展示global filters信息
routefilters GET 展示GatewayFilter factories信息
refresh POST 刷新路由缓存
routes GET 展示路由定义信息
routes/{id} GET 展示单个路由信息
routes/{id} POST 添加新的路由
routes/{id} DELETE 移除路由

开发指南

自定义GatewayFilter Factories

如果想自定义实现GatewayFilterFactory,可以继承AbstractGatewayFilterFactory抽象类。

比如如果想请求前做一些事情,可以类似于下面的实现:

*PreGatewayFilterFactory.java. *

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {

public PreGatewayFilterFactory() {
super(Config.class);
}

@Override
public GatewayFilter apply(Config config) {
// 从config对象中获取配置
return (exchange, chain) -> {
// 在这里做请求前的事情
ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
//重新构造新的request
return chain.filter(exchange.mutate().request(request).build());
};
}

public static class Config {
// 设置配置
}

}

请求后做的是事情,可以如下实现:

PostGatewayFilterFactory.java.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {

public PostGatewayFilterFactory() {
super(Config.class);
}

@Override
public GatewayFilter apply(Config config) {
// 从config对象中获取配置
return (exchange, chain) -> {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
ServerHttpResponse response = exchange.getResponse();
// 在这里做请求后的操作实现
}));
};
}

public static class Config {
// 设置配置
}

}

以上就是spring cloud gateway的其他配置使用讲解,如果想查看其他spring cloud gateway的案例和使用,可以点击查看