Rust时雄到Django通道4 `sec-websocket-key`错误

wfypjpf4  于 2023-10-20  发布在  Go
关注(0)|答案(1)|浏览(81)

我用Rust编写了一个WebSocket客户端,使用tokio_tungstenite::tungstenite::http::Request建立连接,并在ASGI/Daphne 4.0.0开发服务器上运行Django Channels 4服务器。
当我使用当前版本的tokio(特别是0.20)时,我得到以下错误:

Protocol(InvalidHeader("sec-websocket-key"))

然而,当我将tokio降级到0.14时,客户端代码运行没有问题,并且WebSocket连接建立并按预期运行。(注意,我还没有尝试过其他版本之间-它只是碰巧,我以前得到了它的工作0.14,只是想升级到最新版本的这个项目,这恰好是0.20)
经过一点阅读,我明白了密钥是建立WebSocket连接的握手的一部分。然而,tungstenite连接器似乎也应该能够自动生成这个,我不应该在我的头文件中自己设置这个。
这些行可能是最相关的:

let request = Request::builder()
        .uri(&uri)
        .header("Origin", origin)
        .body(()).unwrap();

    let res = connect_async(request).await;
    match res {
       Ok((ws_stream, _)) => {
       ...

请忽略解包-这不是生产代码,我感兴趣的是在使事情变得更好之前解决技术问题。
我是否应该生成一个键,并在头文件中设置它?有没有办法让tungstenite在concert中为我做这件事,而我仍然想设置一个Origin头?还是我忽略了大局
在阅读How to set origin header to websocket client in Rust?之后,我尝试了以下操作:

let request = Request::builder()
        .uri(&uri)
        .header("Host", host)
        .header("Origin", origin)
        .header("Connection", "Upgrade")
        .header("Upgrade", "websocket")
        .header("Sec-WebSocket-Version", "13")
        .header("Sec-WebSocket-Key", tokio_tungstenite::tungstenite::handshake::client::generate_key())
        .body(()).unwrap();

但这会导致另一个错误,表明服务器对尝试不满意:

Http(Response { status: 400, version: HTTP/1.1, headers: {}, body: Some([]) })

如果我降级到0.14,代码甚至不能工作,因为generate_key()在那个版本中是私有的,所以似乎tungstenite不希望我自己调用它(或者至少不习惯)。
tokio 0.14可能做了什么而0.20没有做的事情,我应该如何解决这个问题?

hgtggwj0

hgtggwj01#

用户@kmdreko仔细查看后发现,可能的罪魁祸首是"Host"头字段,它确实是。正在传递字段 *,但没有传递端口号 *。
然而,尽管下面的工作,正确的值为host

let request = Request::builder()
    .uri(&uri)
    .header("Host", host)
    .header("Origin", origin)
    .header("Connection", "Upgrade")
    .header("Upgrade", "websocket")
    .header("Sec-WebSocket-Version", "13")
    .header("Sec-WebSocket-Key", tokio_tungstenite::tungstenite::handshake::client::generate_key())
    .body(()).unwrap();

这有点令人不满意,因为所有这些值都有点随意,我想让tungstenite提供合理的默认值。
这不起作用:

let request = Request::builder()
    .uri(&uri)
    .header("Origin", origin)
    .body(()).unwrap();

这就是我一直在寻找的解决方案:

use tokio_tungstenite::tungstenite::http::HeaderValue;
use tokio_tungstenite::tungstenite::client::IntoClientRequest;

// ..

let mut request = uri.into_client_request().unwrap();
let origin: HeaderValue = origin.parse().unwrap();
request.headers_mut()
    .insert("Origin", origin);

通过将request定义为可变的,然后在tungstenite生成的Request上插入所需的"Origin"字段,我能够得到一个工作解决方案,其中tungstenite将所有其他字段设置为所需的默认/当前设置。

相关问题