我有一个非常简单的带有过滤器的spring-cloud-gateway(扩展了AbstractGatewayFilterFactory
)。
在过滤器内部,我正在使用Spring的RestTemplate
进行REST API调用。其余调用只工作一次,但随后来自过滤器的每个调用都将挂起,并且响应永远不会返回到客户端。
我启用了日志记录以进行跟踪,但是当REST调用挂起时,日志中没有任何内容。
我从@spencergibb的评论here中获悉,阻塞SCG主线程的所有内容都从根本上被破坏了。但是在将请求转发到下游服务之前,我需要确实阻止此API调用。
下面是我的过滤器实现(已删除):
@Component
public class ApiRequestHeaderFilter extends AbstractGatewayFilterFactory<ApiRequestHeaderFilter.Config> {
private static RestTemplate restTemplate = new RestTemplate();
public ApiRequestHeaderFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String someHeaderValue = Objects.requireNonNull(request.getHeaders().get("SOME_HEADER")).get(0);
callRestApi();
return chain.filter(exchange);
};
}
private void callRestApi() {
UriComponentsBuilder uriBuilder = .... //build the API URL
final ResponseEntity<List<MyCustomObject>> response = restTemplate.exchange(uriBuilder.toUriString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<MyCustomObject>>() {
});
.... //process the response
....
}
static class Config {
}
}
答案 0 :(得分:0)
在使用restTemplate进行调用之前,请勿读取(通过读取日志)。 Spring Cloud Gateway需要记录请求正文的内容,但是请求正文只能被读取一次。如果在读取之后未封装请求主体,则后者服务将无法读取主体数据。 follow this
答案 1 :(得分:0)
我认为从 GatewayFilter
调用另一个服务的推荐方式是请求链。
例如为了为每个过滤的请求调用 google:
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> WebClient.create("https://www.google.com")
.method(HttpMethod.GET)
.retrieve()
.bodyToMono(String.class)
.map(s -> {
System.out.println(s);
return exchange;
})
.flatMap(chain::filter);
}
在这个例子中使用了 WebClient
,它是一个与 RestTemplate
不同的非阻塞客户端。
bodyToMono
方法产生的 Mono
可以在所需操作后映射到 exchange
以继续进行过滤。
有关详细信息,请参阅 this great baeldung guide。