Rust tungstenite WebSocket部署Heroku后前端连接失败如何解决
WebSocket连接Heroku部署失败修复方案
1. 先修复前端连接地址格式错误
你当前的WebSocket连接地址存在协议重复问题:wss://本身就是WebSocket加密连接的协议前缀,后面不需要再加https://。现有写法wss://https://myappname.herokuapp.com/会导致URL解析失败,控制台报错里的wss://https//xxx就是解析异常的直接表现。
直接替换为正确写法即可:
var ws = new WebSocket("wss://rocky-wave-51234.herokuapp.com/");
2. 调整后端实现适配Heroku的代理转发规则
你之前查到的「需要先创建HTTP服务再升级为WebSocket连接」的方向完全正确。
Heroku的dyno实例前有一层官方HTTP反向代理,不会将裸TCP流量直接转发到你绑定的端口:所有外部请求(包括WebSocket请求)都会先以标准HTTP格式到达代理,只有携带Connection: Upgrade、Upgrade: websocket头的请求,才会被代理识别为WebSocket连接,转发给后端做协议升级。
你当前直接用tungstenite绑定TCP端口、等待原生WebSocket连接的写法,在本地直连端口时可以正常运行,但在Heroku环境下无法正确处理代理发来的HTTP格式升级握手请求,自然会连接失败。
后端修改要点
不要直接裸监听TCP端口处理WebSocket,先实现基础HTTP服务能力:
- 收到请求后先判断是否为WebSocket升级请求
- 如果是,返回
101 Switching Protocols响应完成握手,再将连接升级为WebSocket连接处理后续逻辑 - 如果是普通HTTP请求(比如Heroku的健康检查请求),返回正常200响应即可,避免健康检查失败被代理判定服务不可用
核心逻辑参考代码(基于tokio生态):
use tokio::net::TcpListener; use hyper::{Request, Response, Body, StatusCode}; use tokio_tungstenite::tungstenite::handshake::derive_accept_key; // 处理入站请求 async fn handle_request(req: Request<Body>) -> Response<Body> { // 校验WebSocket升级请求头 let is_ws_request = req.headers() .get("connection") .and_then(|v| v.to_str().ok()) .map(|v| v.to_ascii_lowercase().contains("upgrade")) .unwrap_or(false) && req.headers() .get("upgrade") .and_then(|v| v.to_str().ok()) .map(|v| v.to_ascii_lowercase() == "websocket") .unwrap_or(false); if is_ws_request { // 完成WebSocket握手,返回101状态码 let ws_key = req.headers() .get("sec-websocket-key") .and_then(|v| v.to_str().ok()) .unwrap(); Response::builder() .status(StatusCode::SWITCHING_PROTOCOLS) .header("Connection", "Upgrade") .header("Upgrade", "websocket") .header("Sec-WebSocket-Accept", derive_accept_key(ws_key.as_bytes())) .body(Body::empty()) .unwrap() } else { // 普通HTTP请求返回200,适配Heroku健康检查 Response::new(Body::from("Chat server running")) } } #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let port = std::env::var("PORT").unwrap_or_else(|_| "8080".to_string()); let addr = format!("0.0.0.0:{}", port); let listener = TcpListener::bind(&addr).await?; println!("Listening on: {}", addr); // 循环接受连接,传入handle_request处理,升级成功后走原有WebSocket聊天逻辑即可 Ok(()) }
如果不想手动写握手逻辑,也可以直接用集成了HTTP路由的Web框架搭配WebSocket插件实现,比如axum、warp都有现成的WebSocket升级能力,不用自己处理握手头校验,代码会更简洁。
验证顺序
- 改完前端地址、后端逻辑后重新部署
- 先直接在浏览器访问你的Heroku应用域名,能看到返回的
Chat server running文本,说明HTTP服务和健康检查正常 - 再打开前端页面测试WebSocket连接,即可正常连通
内容的提问来源于stack exchange,提问作者Agigas
相关产品推荐
相关产品推荐

