当前位置: 首页 > 知识库问答 >
问题:

如何在pythonwebsocket服务器握手响应中设置“secwebsocketprotocol”头?

安泰平
2023-03-14

我有一个pythonwebsocket服务器和一个nodejs客户端,但我无法实现websocket的协议握手。

下面的最小WebSocket服务器使用Flask-Socket(使用gevent-webSocket)。文件名为ws_server.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from flask import Flask, request, Response
from flask_sockets import Sockets

app = Flask(__name__)
sockets = Sockets(app)

@sockets.route('/')
def echo_socket(ws):
    # print("type request: ",type(request))
    # print("dir  request: ", dir(request))
    print("request.headers: ", request.headers)
    # print("type ws: ",type(ws))
    # print("dir  ws: ",dir(ws))

    if hasattr(request, "Sec-Websocket-Protocol"):
        print(request.headers["Sec-Websocket-Protocol"])
    else:
        print("INFO: No protocol specified")

    if request.headers["Sec-Websocket-Protocol"] == "aProtocol":
        print("INFO: protocol is OK")
    else:
        print("INFO: protocol not accepted: closing connection")
        ws.close()

    while not ws.closed:
        message = ws.receive()
        if message:
            print("received: "+message)
            ws.send(message)

    if ws.closed:
        print("INFO: connection has been closed")

if __name__ == "__main__":
    from gevent import pywsgi
    from geventwebsocket.handler import WebSocketHandler
    server = pywsgi.WSGIServer(('', 5001), app, handler_class=WebSocketHandler)
    server.serve_forever()

以下最小websocket客户端使用websocket库。文件名为app。js

'use strict'

var WebSocketClient = require('websocket').client;
var client = new WebSocketClient();

function connectToServer(uri,protocol){
    client.on('connectFailed', function (error) {
        console.log('Connect Error: ' + error.toString());
    });

    client.on('connect', function (connection) {
        console.log('WebSocket Client Connected');

        connection.on('error', function (error) {
            console.log("Connection Error: " + error.toString());
        });

        connection.on('close', function () {
            console.log('echo-protocol Connection Closed');
        });

        connection.on('ping', () => {
            connection.pong();
        });

        connection.on('message', function (message) {
            if (message.type === 'utf8') {
                console.log("Received message is: '" + message.utf8Data + "'");
            }
        });
        console.log("sending SOMETHING");
        connection.sendUTF("SOMETHING");
    });
    client.connect(uri, protocol);
}

const wsHostAndPort = process.env.WSHSTPRT || "ws://echo.websocket.org:80";
const wsProtocol = process.env.WSPRTCL || []; // [] for no protocol

console.log("connecting to: ",wsHostAndPort,"with protocol",wsProtocol);
connectToServer(wsHostAndPort,wsProtocol);

启动python ws-server:

$ python3 ws_server.py

从nodejs ws客户端连接:

$ WSHSTPRT=ws://localhost:5001/ WSPRTCL="aProtocol" node app.js

客户端的输出是

connecting to:  ws://localhost:5001/ with protocol aProtocol
Connect Error: Error: Expected a Sec-WebSocket-Protocol header.

服务器终端的输出为:

request.headers:  Upgrade: websocket
Connection: Upgrade
Sec-Websocket-Version: 13
Sec-Websocket-Key: +QjH5xejDI+OQZQ0OZcWEQ==
Host: localhost:5001
Sec-Websocket-Protocol: aProtocol


INFO: No protocol specified
INFO: protocol is OK
INFO: connection has been closed

在我看来,python服务器需要设置一个名为“Sec WebSocket Protocol”的头,该头的值与它从客户端收到的值相同。但我不知道怎么做。到目前为止,我在互联网上搜索(主要是flask socketsgevent websockets论坛和问题追踪器),没有任何运气。

我尝试了另一个简单的客户端,webSocat。我是这样调用它的:$webocatws://localhost:5001--------------------------------------------------------------------------------------------------------------------------它的工作原理是因为,我认为,webSocket(不像nodejs'webSocket)不希望在与服务器的握手中出现Sec-WebSocket协议头。

但是我需要使用nodejs客户端,它需要头。所以我的问题是:如何在python服务器握手响应中合并“Sec WebSocket协议”头?


共有1个答案

龚同
2023-03-14
匿名用户

我知道这是一年多前的事了,看起来你已经向前看了,尽管看起来你快到了,只是需要用服务器期望的子协议替换一个协议。

或者,完全省略,根据flask-webSocket使用的底层gevent-webSocket:

// Subprotocol (2nd parameter) often is not required at all
var ws = new WebSocket('ws://localhost:5001/api');

对于未来的我或任何在这里跌跌撞撞的人,我希望以下内容有所帮助。

在JavaScript中,将浏览器连接到节点。JS apollo服务器订阅,我需要以下内容:

// Pasted into Firefox console
const token = '...';  // A bearer token, if auth is needed
const subprotocol = 'graphql-ws';
w = new WebSocket('ws://localhost:5000/graphql', subprotocol);
w.send(JSON.stringify({"type":"connection_init","payload":{"authToken":token}}));

否则,如果没有应用子协议,没有发送Sec-WebSock-协议标头,并且控制消息可见,我会看到连接关闭: 1002,并且自然无法向webSock-发送消息:

 类似资料:
  • 我正在使用Progress DataDirect(光荣...)Microsoft SQL Server 2012的JDBC驱动程序 我现在正在尝试使用具有适当java.security文件、罐子、无限强度密码套件的符合FIPS的信任存储与我的java客户端应用程序连接到它们。信任存储包含我自己的CA的自签名证书。使用的算法是RSA。 使用JDK 1.7.0_。之后,它只是通过连接重置断开连接。 此

  • 我想在每个响应中添加etag属性。我已经在响应中添加了varie-header和cache-control header(最大age=600,public),但是我没有找到任何在响应中添加etag的解决方案。有人能帮帮我吗?

  • 问题内容: 这是我的代码: 但是,当我从浏览器向服务器发出请求时,出现此错误: 我也尝试过这种方法,在请求之后设置响应头: 没有骰子。我犯了同样的错误。有没有一种方法可以只在route函数中设置响应头?这样的事情将是理想的: 但我还是找不到这样做。请帮忙。 编辑 如果我使用POST请求卷曲URL,如下所示: 我得到这个回应: 有任何想法吗? 问题答案: 你可以很容易地做到这一点: 查看和 但是有些

  • 我使用PHP-S127.0.0.1:4242命令在本地主机上为php文件启动development server。但我想,我不应该在生产中使用这个东西。目前我正在尝试在VPS上设置我的网站,我不知道如何在端口4242上永远使用ssh启动php服务器。我知道,这可能是很愚蠢的问题,这是我第一次与真正的主持工作 如有任何帮助,我将不胜感激:)

  • 通过设置本地计算机、开发服务器、中间服务器或生产服务器作为测试服务器,测试动态网页或内容。 如果您计划使用服务器端语言(如 PHP)开发动态页,请设置一个测试服务器以便在您进行操作时生成并显示动态内容。 测试服务器可以是本地计算机、开发服务器、中间服务器或生产服务器。 要详细了解测试服务器的用途,请参阅 David Powers 的文章 Setting up a local testing ser

  • 我有一个无服务器API,它与无服务器框架版本1.25一起工作 由于安全原因,我想添加响应头。请帮助我如何通过serverless.yml文件设置下面的标题。出于安全考虑,有必要添加此标题吗? 内容-安全-策略:包括默认-src“自我” •严格的交通安全最大年龄=31536000;包括子域;预载 •X-Content-Type-Options:nosniff •X-XSS-保护:1 •缓存控制:最大