Spring Cloud Gateway MVC频繁抛IO异常,路由403失败求助
问题描述
正在从Zuul迁移至Spring Cloud Gateway MVC,使用Spring Boot 3.2.3 + spring-cloud-starter-gateway-mvc 4.1.0,配置了如下路由:
spring: cloud: gateway: mvc: routes: - id: rabbitmq uri: http://localhost:15672/ predicates: - Path=/rabbitmq/** - Method=GET, POST filters: - StripPrefix=1
本地环境下转发正常,但服务器上频繁抛出IO异常:
java.io.IOException: closed at java.net.http/jdk.internal.net.http.ResponseSubscribers$HttpResponseInputStream.current(ResponseSubscribers.java:460) ~[java.net.http:na] at java.net.http/jdk.internal.net.http.ResponseSubscribers$HttpResponseInputStream.read(ResponseSubscribers.java:499) ~[java.net.http:na] at java.base/java.io.InputStream.transferTo(InputStream.java:782) ~[na:na] at org.springframework.util.StreamUtils.copy(StreamUtils.java:150) ~[spring-core-6.1.4.jar:6.1.4] at org.springframework.cloud.gateway.server.mvc.handler.RestClientProxyExchange.lambda$doExchange$3(RestClientProxyExchange.java:52) ~[spring-cloud-gateway-server-mvc-4.1.0.jar:4.1.0] at org.springframework.cloud.gateway.server.mvc.handler.GatewayServerResponseBuilder$WriteFunctionResponse.writeToInternal(GatewayServerResponseBuilder.java:218) ~[spring-cloud-gateway-server-mvc-4.1.0.jar:4.1.0] at org.springframework.cloud.gateway.server.mvc.handler.AbstractGatewayServerResponse.writeTo(AbstractGatewayServerResponse.java:103) ~[spring-cloud-gateway-server-mvc-4.1.0.jar:4.1.0] at org.springframework.web.servlet.function.support.HandlerFunctionAdapter.handle(HandlerFunctionAdapter.java:111) ~[spring-webmvc-6.1.4.jar:6.1.4]
已尝试调整Spring Boot安全配置、HTTP客户端连接超时属性,问题未解决。
可能原因分析
- 服务器端连接提前关闭:RabbitMQ管理端或服务器网络层(防火墙、反向代理)在响应完全传输前关闭了连接,导致Gateway读取响应流时出错。
- RestClient默认配置不匹配服务器环境:Spring Cloud Gateway MVC使用的RestClient默认连接/超时设置不适应服务器网络延迟,或缺少连接池配置导致连接频繁被回收。
- 响应流处理时序问题:Gateway异步转发响应时,可能因流处理逻辑的时序问题导致输入流被提前关闭。
排查与解决步骤
1. 验证服务器上RabbitMQ管理端状态
- 直接在服务器上访问
http://localhost:15672,确认响应正常无中断、超时。 - 查看RabbitMQ日志,排查是否存在连接中断、资源不足(文件句柄、内存)等问题。
2. 自定义RestClient配置,优化连接与超时
通过代码或配置文件调整RestClient的连接池、超时参数,适配服务器环境:
代码方式自定义RestClient
import org.springframework.cloud.gateway.server.mvc.config.ProxyExchangeCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestClient; import java.time.Duration; @Configuration public class GatewayRestClientConfig { @Bean public ProxyExchangeCustomizer proxyExchangeCustomizer() { return exchange -> exchange.restClient( RestClient.builder() .connectTimeout(Duration.ofSeconds(10)) .readTimeout(Duration.ofSeconds(30)) .build() ); } }
配置文件调整底层HttpClient参数
spring: cloud: gateway: mvc: httpclient: connect-timeout: 10000 response-timeout: 30000 pool: max-idle-time: 30s max-life-time: 60s
3. 调整响应流处理策略(小响应体场景适用)
将响应体缓冲到内存后再转发,避免流提前关闭的问题:
import org.springframework.cloud.gateway.server.mvc.filter.GatewayFilterFunctions; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.RouterFunctions; import org.springframework.web.servlet.function.ServerResponse; @Configuration public class GatewayRouteConfig { @Bean public RouterFunction<ServerResponse> rabbitmqRoute() { return RouterFunctions.route() .path("/rabbitmq/**", builder -> builder .GET() .POST() .route(req -> req .proxy() .uri("http://localhost:15672") .filter(GatewayFilterFunctions.stripPrefix(1)) .filter((req, exchange) -> { // 缓冲响应内容后再返回 return exchange.retrieve() .bodyToMono(byte[].class) .flatMap(body -> ServerResponse.ok().bodyValue(body)); }) ) ) .build(); } }
注:该方式会将响应体全部加载到内存,不适合大文件传输场景。
4. 检查服务器网络环境
- 确认服务器防火墙/安全组未限制本地端口15672的访问。
- 若服务器使用反向代理(如Nginx),检查代理的超时、缓冲配置,避免提前关闭连接。
内容的提问来源于stack exchange,提问作者Gowtham M
相关产品推荐
相关产品推荐

