来自spring-cloud-gateway过滤器的RestTemplate调用挂起

时间:2019-08-18 11:45:43

标签: spring resttemplate spring-cloud-gateway

我有一个非常简单的带有过滤器的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 {
    }
}

2 个答案:

答案 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