Spring Cloud Gateway 4.1.0使用WebClient同步调用闲置1分钟后挂起求解决方案
Spring Cloud Gateway版本:4.1.0
我们基于Spring Cloud Gateway框架开发API网关应用,已实现多个全局有序的前置过滤器和后置过滤器。其中一个全局前置过滤器用于在请求路由到目标端点前,调用其他微服务暴露的REST API校验用户会话令牌以完成认证,代码实现如下:
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { final String sessionToken = exchange.getRequest().getHeaders().getFirst("sessionToken"); final boolean isValid = restApiConnector.validateSessionToken(exchange, sessionToken) // 基于WebClient调用校验令牌的REST API .subscribeOn(Schedulers.boundedElastic()) .publishOn(Schedulers.boundedElastic()) .toFuture().get(); // 阻塞调用 exchange.getAttributes().put("sessionStatus", isValid); return chain.filter(exchange); }
注:修正了原代码中的两处笔误:
getRequest().getHeader()改为getRequest().getHeaders(),Scheduleers拼写修正为Schedulers
restApiConnector是基于Spring WebClient实现的REST API调用连接器,validateSessionToken方法通过调用会话校验接口验证令牌合法性。
此处刻意采用阻塞(同步)调用,原因是后续所有前置过滤器都依赖该会话校验的结果,且仅当令牌校验通过时,请求才会路由到下游端点。因此该前置过滤器必须在所有后续前置过滤器、下游端点及后置过滤器之前执行。
按照长时I/O或网络调用需在独立线程执行以避免阻塞Netty主线程的建议,我们使用了subscribeOn和publishOn方法指定在boundedElastic线程池中执行。
目前代码的表现是:请求发送至网关后能正常完成校验并路由;若在最后一次请求的1分钟内发送多个请求,应用也能正常工作。
但如果在最后一次请求后闲置1分钟再发送请求,请求处理会在REST API调用处挂起,且不会向会话校验服务器发送请求。此时网关仍能接收后续请求,但所有后续请求均会出现相同的挂起行为。
我们已查阅相关资料,多数建议使用发布者的**block()**调用,但该方法每次请求都会抛出异常,因此改用toFuture().get()。另外我们无法使用subscribe(),因为这会使REST API调用变为异步,可能导致校验逻辑在前置过滤器和后置过滤器执行完成后才被调用,不符合预期的请求处理流程。
请指导此类场景下进行网络REST API同步调用的最佳实践。
内容的提问来源于stack exchange,提问作者Deepak Chhetri

