16. 问题定位
本节覆盖Spring Cloud Gateway开发过程中可能会遇到的问题。
16.1. 日志级别
把下面的包日志级别设置为DEBUG或TARCE可能会看到更多的参数信息:
- org.springframework.cloud.gateway
- org.springframework.http.server.reactive
- org.springframework.web.reactive
- org.springframework.boot.autoconfigure.web
- reactor.netty
- redisratelimiter
16.2. 监听请求
Reactor Netty 的 HttpClient 和 HttpServer 可以开启监听功能。结合设置包reactor.netty 的日志级别设置到debug或trace,会打印出请求的header和body信息。要启动监听功能,设置 spring.cloud.gateway.httpserver.wiretap=true 或 spring.cloud.gateway.httpclient.wiretap=true 开启httpServer或HttpClient 的监听。
17 自定义组件
下面有一些编写网关自定义组件的基本指导。
17.1. 编写自定义路由断言
编写路由断言需要实现接口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
}
}
17.2. 自定义GatewayFilter
编写GatewayFilter,必须实现接口GatewayFilterFactory。那里有一个抽象类AbstractGatewayFilterFactory可以继承。
Example 74. 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.2.1. 自定义过滤器命名和配置
自定义过滤器的类名应该以GatewayFilterFactory结尾。
比如,在配置文件中引用一个名叫Something的过滤器,该过滤器的类名必须为SomethingGatewayFilterFactory。
注意
网关过滤器的名字可以不以GatewayFilterFactory结尾,比如class AnotherThing。这个过滤器也可以通过AnotherThing在配置文件中引用。但是那不是一个支持的命名约定,在未来的版本中会被移除。请更新过滤器名字以符合约定。
17.3. 自定义全局过滤器
自定义全局过滤器,必须实现GlobalFilter接口。过滤器会应用到所有的请求中。
下面是设置pre和post过滤器的例子:
@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 handler的方法参数中使用。它支持基本的http请求。通过MVC,也支持通过forward()方法转发到本地的handler。需要添加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特性都可以在网关的handler方法中使用。因此,你可以往请求中注入请求参数和header;也可以在Mapping注解中约束进入的请求。具体请看Spring MVC的@RequestMapping文档。
通过ProxyExchange的header()方法,你可以添加header到响应中。
你也可以给get()方法(或者其它方法)添加一个mapper,以修改响应的header(或响应中的其它东西)。mapper是获得的ResponseEntity中的方法,转化为返回的响应。
优先支持的是提供敏感的header(默认是cookie和authorization),那是不会传递到下游的。也可以添加代理(x-forwarded-*) header
Spring Cloud Gateway 2.2.3 官方使用说明(1)–路由
Spring Cloud Gateway 2.2.3 官方使用说明(2)-- 路由filter(上)
Spring Cloud Gateway 2.2.3 官方使用说明(2)-- 路由filter(下)
Spring Cloud Gateway 2.2.3 官方使用说明(3)-- Global filter
Spring Cloud Gateway 2.2.3 官方使用说明(4)-- HttpHeader Filters
Spring Cloud Gateway 2.2.3 使用说明(5)-- TLS 和 SSL
Spring Cloud Gateway 2.2.3 使用说明(6)-- 其它配置
Spring Cloud Gateway 2.2.3 使用说明(7)-- actuator