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

基于Tungstenite的基础WebSocket服务器握手失败求助

问题分析与解决方案

核心问题

你遇到的HandshakeError::Failure(Protocol(HttparseError(Token)))错误,根源是客户端使用了加密WebSocket协议(wss://),但你的服务器是普通TCP的WebSocket服务(仅支持ws://),两者协议不匹配导致握手失败。

快速修复方案:修改客户端连接协议

直接把客户端代码里的wss://改成ws://即可:

<script type="application/javascript">
    // 把 wss:// 替换为 ws://
    var ws = new WebSocket("ws://127.0.0.1:3012");
    ws.onopen = function () {
        console.log('Connection is open...')
        ws.send("Hello from client");
    };
    ws.onmessage = function (evt) {
        console.log(evt.data);
    };
    ws.onclose = function () {
        console.log("Connection is closed...");
    };
    window.ws = ws;
    console.log('Client is ready')
</script>

修改后重启客户端和服务器,即可正常建立连接。

进阶方案:让服务器支持WSS(加密WebSocket)

如果需要使用wss://,你需要给服务器配置TLS证书(测试环境可用自签名证书),步骤如下:

1. 生成自签名证书(测试用)

用OpenSSL生成证书和密钥:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

执行命令后按提示填写信息,生成key.pem和cert.pem文件,放到项目根目录。

2. 修改服务器代码支持TLS

更新Cargo.toml依赖:

[dependencies]
tungstenite = { version = "0.20", features = ["native-tls"] }
native-tls = "0.2"

修改服务器代码,用TLS包装TCP流:

use std::{net::TcpListener, thread::spawn};
use native_tls::{Identity, TlsAcceptor};
use tungstenite::{
    accept_hdr,
    handshake::server::{Request, Response},
};

fn main() {
    // 加载证书和密钥
    let cert = include_bytes!("cert.pem");
    let key = include_bytes!("key.pem");
    let identity = Identity::from_pkcs8(cert, key).unwrap();
    let acceptor = TlsAcceptor::new(identity).unwrap();

    let server = TcpListener::bind("127.0.0.1:3012").unwrap();
    for stream in server.incoming() {
        let acceptor = acceptor.clone();
        spawn(move || {
            // 用TLS包装TCP流
            let stream = acceptor.accept(stream.unwrap()).unwrap();
            
            let callback = |req: &Request, mut response: Response| {
                println!("Received a new ws handshake");
                println!("The request's path is: {}", req.uri().path());
                println!("The request's headers are:");
                for (ref header, _value) in req.headers() {
                    println!("* {}", header);
                }

                let headers = response.headers_mut();
                headers.append("MyCustomHeader", ":)".parse().unwrap());
                headers.append("SOME_TUNGSTENITE_HEADER", "header_value".parse().unwrap());

                Ok(response)
            };
            let mut websocket = accept_hdr(stream, callback).unwrap();

            loop {
                let msg = websocket.read_message().unwrap();
                if msg.is_binary() || msg.is_text() {
                    websocket.write_message(msg).unwrap();
                }
            }
        });
    }
}

此时客户端可以继续使用wss://127.0.0.1:3012连接(浏览器可能会提示证书不安全,测试环境下忽略即可)。

补充说明

  • 你之前添加的features = ["native-tls"]是正确的,但缺少TLS流的包装逻辑,所以没生效。
  • 移除accept_hdr改用accept无法解决问题,因为核心是协议不匹配,和回调无关。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 00:47:33