Spring Cloud Gateway 和 Nginx 网关代理 WebSocket 路由配置
内容提要
该项目需在Spring Cloud Gateway公网网关配置入口,经Nginx代理转发至后端服务,支持HTTP和WebSocket请求。文章详细说明了Gateway和Nginx的路由配置方法,包括WebSocket握手头处理、路径前缀剥离、SSL证书配置及超时设置,并提供了验证步骤和常见错误排查表,如协议错误、SSL握手失败等问题的解决方案。
延伸解读
路径前缀剥离的陷阱
在Nginx配置中,proxy_pass末尾的斜杠决定了是否剥离路径前缀。若proxy_pass http://app_cluster/,则/ws/前缀会被去掉;若不加斜杠,则保留。Spring Cloud Gateway中应避免使用StripPrefix,因为它会破坏WebSocket握手头。理解这一差异有助于正确配置路由,避免后端因路径不匹配而返回404或握手失败。
WebSocket握手的关键头
WebSocket握手依赖Upgrade和Connection头,Nginx需通过proxy_set_header显式传递,并使用HTTP/1.1。Spring Cloud Gateway需确保路由uri以ws://或lb:ws://开头,并避免StripPrefix。若这些头未正确传递,客户端会收到1002协议错误或426升级要求。配置时务必检查这些头是否被正确转发。
SSL证书与协议兼容性
当使用wss://时,Nginx需配置SSL证书,并确保TLS版本和加密套件兼容。若后端使用自签名证书,可设置proxy_ssl_verify off(测试环境)或指定CA证书。客户端测试时可用-k或--insecure跳过验证。证书域名不匹配或TLS版本不兼容会导致SSL握手失败,需检查证书配置和协议支持。
超时与长连接维护
WebSocket长连接需设置较长的超时时间,如Nginx的proxy_read_timeout和proxy_send_timeout设为3600s,并关闭缓冲以提升实时性。若超时过短,连接可能被意外断开。此外,可配置心跳(Ping/Pong)保持连接活跃,避免因空闲超时导致连接中断。
Q&A
如何在Spring Cloud Gateway中配置WebSocket路由?
在Spring Cloud Gateway中,需要定义一个路由,其uri使用ws://或wss://(或lb:ws://),predicates匹配路径和Upgrade头,例如Path=/ws/**和Header=Upgrade, websocket。同时,不要使用StripPrefix过滤器,因为它会破坏WebSocket握手头,应使用PreserveHostHeader保持Host头不变。
Nginx代理WebSocket时如何配置Upgrade和Connection头?
在Nginx的location配置中,需要设置proxy_http_version 1.1,并使用map定义$connection_upgrade变量,然后通过proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection $connection_upgrade;来传递Upgrade和Connection头,确保WebSocket握手成功。
在Nginx中如何去掉/ws/前缀并转发到后端?
在Nginx的location /ws/配置中,使用proxy_pass http://app_cluster/;,注意末尾的斜杠,这样会将/ws/前缀去掉,将请求转发到后端的根路径。如果不加末尾斜杠,则会保留/ws/前缀。
WebSocket连接返回1002协议错误是什么原因?
1002协议错误通常是因为反向代理未转发Upgrade和Connection头,或使用了HTTP/1.0,或子协议协商失败,或客户端发送了非掩码帧。解决方法包括配置Nginx的proxy_http_version 1.1和Upgrade头,确保客户端使用正确的子协议,并检查数据帧格式。
如何验证Spring Cloud Gateway和Nginx的WebSocket路由配置是否正确?
可以使用curl命令模拟WebSocket握手,发送带有Upgrade和Connection头的请求,预期返回101 Switching Protocols。也可以使用websocat工具测试ws和wss连接。此外,可以查看Gateway和Nginx的日志,以及分阶段验证后端、Nginx和Gateway。
Nginx代理后端为WSS时如何配置SSL验证?
当后端使用WSS时,在Nginx的location中设置proxy_pass https://backend_server:8443/;,并配置proxy_ssl_verify off;(测试环境)或指定CA证书链proxy_ssl_trusted_certificate /path/to/ca.pem;。同时需要传递Upgrade和Connection头。
WebSocket连接建立后立即断开可能是什么原因?
可能原因包括代理或负载均衡器的空闲超时太短(默认60秒),客户端未发送心跳,或后端应用主动关闭连接。解决方法包括增大代理超时(如proxy_read_timeout 3600s),客户端定期发送Ping帧,并检查后端日志。