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

使用Rust Tokio Tungstenite构建WebSocket客户端时遭遇400错误求助

使用tokio-tungstenite连接Coinbase WebSocket时出现400 Bad Request的解决方法

问题原因

Coinbase的WebSocket Feed服务器会校验请求的User-Agent头部,而tokio_tungstenite::connect_async默认不会携带该头部,导致服务器返回400 Bad Request。浏览器插件会自动添加合法的User-Agent,因此能正常连接。

解决方案

通过自定义HTTP握手请求,添加符合要求的User-Agent头部,使用tokio_tungstenite::client_async方法发起连接。

修改后的代码

use std::env;
use futures::{SinkExt, StreamExt};
use tokio_tungstenite::{client_async, tungstenite::protocol::Message};
use hyper::{Request, header::USER_AGENT};
use hyper_tls::HttpsConnector;

#[tokio::main]
async fn main() {
    env::set_var("RUST_BACKTRACE", "1");

    let url = "wss://ws-feed.exchange.coinbase.com";
    let msg = r#"
    {
        "type": "subscribe",
        "product_ids": [
            "ETH-USD"
        ],
        "channels": [
            "level2",
            "heartbeat",
            {
                "name": "ticker",
                "product_ids": [
                    "ETH-USD"
                ]
            }
        ]
    }"#;

    // 构建HTTPS连接器
    let https_connector = HttpsConnector::new();
    let client = hyper::Client::builder().build::<_, hyper::Body>(https_connector);

    // 构造WebSocket握手请求,添加User-Agent头
    let mut req = Request::get(url)
        .header(USER_AGENT, "rust-tokio-tungstenite-client/0.1")
        .body(hyper::Body::empty())
        .unwrap();

    // 添加WebSocket升级所需的标准头
    tokio_tungstenite::add_websocket_headers(&mut req);

    match client_async(req, client).await {
        Ok((ws_stream, _)) => {
            let (mut write, mut read) = ws_stream.split();

            match write.send(Message::Text(msg.to_string())).await {
                Ok(_) => println!("Message sent successfully"),
                Err(e) => println!("Failed to send message: {}", e),
            }

            while let Some(msg) = read.next().await {
                match msg {
                    Ok(msg) => println!("Received: {}", msg),
                    Err(e) => println!("Error reading message: {}", e),
                }
            }
        },
        Err(e) => println!("Failed to connect: {}", e),
    }
}

更新Cargo.toml依赖

需要补充hyper和hyper-tls依赖:

[dependencies]
futures = "0.3"
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.15.0"
hyper = "0.14"
hyper-tls = "0.5"

说明

  • User-Agent头是解决问题的核心,你可以使用自定义标识,也可以使用贴近浏览器的标识(比如Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36)。
  • client_async方法允许完全控制握手请求的头部,弥补了connect_async默认缺少必要头的缺陷。
  • 修改后重新运行代码,即可成功建立连接并接收Coinbase的WebSocket数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 13:35:15