GCP Cloud Run返回0字节响应:SpringBoot非阻塞接口排查求助
问题:SpringBoot非阻塞接口在Cloud Run返回0字节响应,但日志显示响应大小正常
我们将Java SpringBoot应用从Heroku迁移至GCP Cloud Run,为优化性能把REST接口改成非阻塞方式后出现异常:相关接口在Cloud Run上返回0字节响应(浏览器、cURL调用均出现此问题),但Cloud Run日志里显示的responseSize是正常的(比如responseSize: "1137")。
已尝试的排查操作(均未解决)
- 开启公网直接访问Cloud Run,排除负载均衡的影响
- 将内置容器从Tomcat替换为Jetty,排除容器本身的问题
- 尝试使用两代不同的Cloud Run实例
该接口在本地开发环境及Docker容器中运行完全正常,仅部署到Cloud Run时出现0字节响应的问题。
更新:cURL详细调用日志(cURL -L -i -v输出)
Trying 34.36.35.1:443... Connected to ***** (34.36.35.1) port 443 (#0) ALPN, offering h2 ALPN, offering http/1.1 successfully set certificate verify locations: CAfile: /etc/ssl/cert.pem CApath: none (304) (OUT), TLS handshake, Client hello (1): (304) (IN), TLS handshake, Server hello (2): (304) (IN), TLS handshake, Unknown (8): (304) (IN), TLS handshake, Certificate (11): (304) (IN), TLS handshake, CERT verify (15): (304) (IN), TLS handshake, Finished (20): (304) (OUT), TLS handshake, Finished (20): SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256 ALPN, server accepted to use h2 Server certificate: subject: CN=*********** start date: Jun 15 15:58:36 2023 GMT expire date: Sep 13 16:52:50 2023 GMT subjectAltName: host "***********" matched cert's "*" issuer: C=US; O=Google Trust Services LLC; CN=GTS CA 1D4 SSL certificate verify ok. Using HTTP2, server supports multiplexing Connection state changed (HTTP/2 confirmed) Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 Using Stream ID: 1 (easy handle 0x12c00e000) GET /api/user/permissions HTTP/2 Host: ************* user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0 // 部分无关请求头已省略 < HTTP/2 200 < vary: Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Accept-Encoding,User-Agent < cache-control: no-cache, must-revalidate, no-transform,no-store < x-content-type-options: nosniff < x-xss-protection: 1; mode=block < referrer-policy: origin-when-cross-origin < content-type: application/json < x-cloud-trace-context: 1dfe301ceac344ebb4b30eed4c89a495;o=1 < date: Wed, 05 Jul 2023 16:02:11 GMT < server: Google Frontend < content-length: 0 < via: 1.1 google < strict-transport-security: 31536000 < alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 Connection #0 to host ************ left intact
可能的原因
- HTTP/2协议兼容性问题:从cURL日志看,Cloud Run使用HTTP/2协议,非阻塞接口的响应流处理可能在HTTP/2分帧机制下存在适配异常——比如响应流未正确关闭、分帧标记缺失,导致Google Frontend(GFE)无法识别完整响应体,最终返回
content-length:0,但容器内部日志仅记录了已写入的字节数。 - 非阻塞响应未正确完成:Spring WebFlux的非阻塞接口如果返回的
Flux/Mono未触发onComplete信号,容器会认为响应未完成,但Cloud Run日志仍会记录已写入的字节数,GFE则会因未收到完整信号截断响应。 - 响应头与响应体不匹配:代码中若手动设置了
Content-Length但实际响应体大小不符,或非阻塞框架自动处理响应头时出现异常,会导致GFE忽略响应体。 - Cloud Run CPU分配策略影响:若实例采用请求触发的CPU分配(而非持续分配),非阻塞响应流处理过程中CPU被回收,可能导致响应未完整发送。
等待官方支持期间的排查方向
- 强制使用HTTP/1.1测试:用cURL添加
--http1.1参数调用接口,验证是否是HTTP/2兼容性问题:curl -L -i -v --http1.1 https://<你的Cloud Run域名>/api/user/permissions - 检查非阻塞接口代码:
- 确认返回的
Mono/Flux是否正确终止(无无限流、已触发完成信号); - 排查自定义拦截器/过滤器是否消耗了响应流但未正确传递。
- 确认返回的
- 添加容器内响应日志:在应用中记录响应体生成、写入及完成信号的触发细节,对比Cloud Run日志的
responseSize,确认容器内是否生成了完整响应。 - 测试极简非阻塞接口:编写仅返回固定字符串的极简非阻塞接口(如
return Mono.just("{\"test\":1}")),部署后验证是否能正常返回响应,排除业务逻辑干扰。 - 调整Cloud Run实例配置:将实例CPU设置为"持续分配",验证是否因CPU回收导致响应中断。
- 捕获容器内网络流量:在容器内使用
tcpdump捕获发送给GFE的响应数据包,确认容器是否确实发送了完整响应体。
内容的提问来源于stack exchange,提问作者enterbios
相关产品推荐
相关产品推荐

