Search code examples
javascriptrustrust-tokiorust-axum

Why does the web socket give an error when connecting to the server?


I am trying to connect to a web socket on the server, to which the socket gives an error stating that it was failed to connect

Rust code:

use axum::{
    extract::{ws::WebSocket, WebSocketUpgrade},
    response::IntoResponse,
    routing::get,
    Router,
};
use tokio::net::TcpListener;
use tower_http::services::ServeDir;

#[tokio::main]
async fn main() {
    let listener = TcpListener::bind("localhost:3000").await.unwrap();
    axum::serve(listener, router()).await.unwrap();
}

fn router() -> Router {
    Router::new()
        .route("/message_list", get(hello_world))
        .nest_service("/", ServeDir::new("static"))
}

async fn hello_world(ws: WebSocketUpgrade) -> impl IntoResponse {
    let _res = ws.on_upgrade(|ws| socet_handler(ws));
}

async fn socet_handler(mut ws: WebSocket) {
    println!("IT READY!");
    let _res = ws.send(axum::extract::ws::Message::Text("hi".to_string()));
}

js code:

let socket = new WebSocket("ws://localhost:3000/message_list")

I also tried to change 'ws' to 'wss' in the URL but it doesnt help. there is a constant error on the site:

WebSocket connection to 'ws://localhost:3000/message_list' failed

What could this be related to?


Solution

  • Your socet_handler doesn't keep the websocket connection alive, it sends a message and then immediately ends the function - dropping the websocket.

    Try adding a loop listening for messages like in the documentation:

    async fn socet_handler(mut socket: WebSocket) {
        println!("IT READY!");
        let _res = ws.send(axum::extract::ws::Message::Text("hi".to_string())).await;
    
        while let Some(msg) = socket.recv().await {
            // handle the message
        }
    }
    

    Your code also discards the response created from on_upgrade and returns an empty (()) response instead. Remove the let _res = part and let it return like this:

    async fn hello_world(ws: WebSocketUpgrade) -> impl IntoResponse {
        ws.on_upgrade(|ws| socet_handler(ws))
    }
    

    You also were not .await-ing the send call, which means it wouldn't actually send.