











最近有个小程序项目客户在并网时有个需求:需要在他们的Spring Cloud Gateway 公网网关开个入口,打到自建的Nginx代理转发到后端服务,需要同时能支持 http 和 ws 的请求。整体访问链路从公网 → Spring Cloud Gateway → Nginx → 应用服务。主要的工作是Spring Cloud Gateway 和 Nginx 的路由配置和整个链路的联调,mark一下。
spring: cloud: gateway: routes: # 1. WebSocket 路由:处理 WebSocket 握手请求 - id: websocket_route uri: wss://your-backend-service # 非加密的 WebSocket 协议使用 ws:// predicates: # 匹配 /ws/ 路径及其子路径,并确保包含 Upgrade 头 - Path=/ws/** - Header=Upgrade, websocket filters: # 不要用 StripPrefix,会破坏 WebSocket 握手头 - name: SetResponseHeader args: name: Sec-WebSocket-Accept value: ".*" # 让后端自行生成 # 保持 Host 头不变 - name: PreserveHostHeader # 2. HTTP 路由:处理普通的 HTTP 请求处理(处理非 WebSocket 请求) - id: http_route # 普通的 HTTP 负载均衡 uri: lb://your-backend-service predicates: # 匹配相同的路径 - Path=/ws/** filters: # 显式保证查询参数透传 - StripPrefix=0 # 全局 CORS 配置(可选) globalcors: cors-configurations: '[/**]': allowed-origins: "*" allowed-methods: "*" allowed-headers: "*" allow-credentials: true
http {
# 定义 connection_upgrade 变量
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream app_cluster {
server 127.0.0.1:8080;
# 可添加多个 app 实例
}
# ---------- HTTP 服务器(提供 ws://)----------
server {
listen 80;
server_name test.com.cn; # 内网域名或 IP
location /ws/ {
# 去掉 /ws/ 前缀,将请求转发到后端根路径
proxy_pass http://app_cluster/;
# 必须的 WebSocket 握手配置
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# 传递原始 Host 和客户端 IP
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 超时设置(长连接)
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
# 其他非 /ws/ 请求
location / {
proxy_pass http://app_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
# ---------- HTTPS 服务器(提供 wss://)----------
server {
listen 443 ssl;
server_name test.com.cn;
# 网关自身的 SSL 证书(客户端信任的证书)
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location /ws/ {
proxy_pass http://app_cluster/; # 注意末尾斜杠,可去掉 /ws/ 前缀,不加末尾"/" 会保留 /ws/ 前缀
# 关键:WebSocket 握手依赖 HTTP/1.1
proxy_http_version 1.1;
# 传递 WebSocket 升级头
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# 传递原始信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; # 告诉后端客户端实际使用的是 HTTPS(当后端需要区分协议时有用)
# 长连接超时(避免空闲断开)
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
# 关闭缓冲,提升实时性
proxy_buffering off;
}
# 其他非 /ws/ 请求
location / {
proxy_pass http://app_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}如果后端 WebSocket 服务器也要求使用 WSS(例如 https://backend_server:8443),则需额外处理 SSL 验证:
location /ws/ {
proxy_pass https://backend_server:8443/; # 使用 HTTPS 协议
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 如果后端使用自签名证书,关闭 SSL 验证(测试环境)
proxy_ssl_verify off;
# 或者指定 CA 证书链:proxy_ssl_trusted_certificate /path/to/ca.pem;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
# 强制将 HTTP 重定向到 HTTPS(可选配置)
server {
listen 80;
server_name test.com.cn;
return 301 https://$host$request_uri;
}关键检查项:
确认 proxy_pass 的 URL 正确:如果你想去掉 /ws/ 前缀,proxy_pass 末尾要带 /,如 proxy_pass http://backend/;。
确认后端能接收未加密流量:如果网关 Nginx 处理了 HTTPS(WSS),那么它转发给下游 Nginx 的可以是 HTTP(WS)。请确保你的下游 Nginx 和后端服务能正确处理这种转发。
启用会话保持 (Sticky Sessions):对于有状态的应用,应在目标组(Target Group)上启用会话保持,确保来自同一客户端的请求始终到达同一后端。
检查安全组:确保 LB 的安全组允许来自客户端和去往后端的目标端口(如 80/443)的流量。
curl -v -H "Host: test.com.cn" \ -H "Connection: Upgrade" \ -H "Upgrade: websocket" \ -H "Sec-WebSocket-Key: $(openssl rand -base64 16)" \ -H "Sec-WebSocket-Version: 13" \ https://网关IP:网关端口/ws/channel/checkHost?id=xxx
预期返回 101 Switching Protocols。
使用 websocat 工具测试:brew install websocat(mac安装)
使用 websocat ws://test.com.cn/ws/ 测试 WS。
使用 websocat -k wss://test.com.cn/ws/ 测试 WSS(自签名证书需加 -k 忽略验证)。
测试普通 HTTP 请求:
curl -v https://test.com.cn/ws/channel/checkHost?id=xxx
应正常返回业务数据。
在 application.yml 中为 org.springframework.cloud.gateway 开启 DEBUG 级别日志,观察请求被匹配到了哪条路由。
logging: level: org.springframework.cloud.gateway: DEBUG org.springframework.web: DEBUG
观察请求被哪个路由匹配。
查看 Nginx 错误日志:
tail -f /var/log/nginx/error.log,可定位连接后端失败或 SSL 错误。
tail -f /var/log/nginx/access.log,可观察请求被哪个路由匹配。
先验证后端服务是否正常,然后排查 Nginx 配置,再访问 Gateway 服务(绕过 Nginx),确认 Gateway 配置。
测试验证后端服务 ws 连接是否正常
再通过 Nginx 访问:https://test.com.cn/ws/...
访问 Gateway(绕过 Nginx):https://网关IP:端口/ws/...
在配置 WebSocket 代理或客户端时,最常见的错误往往源于反向代理(如 Spring Cloud Gateway、Nginx)的配置缺失、网络环境干扰或 SSL/TLS 证书问题。下表汇总了典型错误现象、可能原因及对应解决方案,快速定位问题。
参考:
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。