You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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升级能力,不用自己处理握手头校验,代码会更简洁。

验证顺序

  1. 改完前端地址、后端逻辑后重新部署
  2. 先直接在浏览器访问你的Heroku应用域名,能看到返回的Chat server running文本,说明HTTP服务和健康检查正常
  3. 再打开前端页面测试WebSocket连接,即可正常连通

内容的提问来源于stack exchange,提问作者Agigas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 19:51:18