【问题标题】:Quart python : send websocket broadcast message from curl and display itQuart python:从curl发送websocket广播消息并显示它
【发布时间】:2021-02-10 17:07:24
【问题描述】:

我是这样编辑的:

我的 curl 命令是:

curl -d '{"key1":"value1", "key2":"value2"}' -H "Content-Type: application/json" -X POST http://localhost:5000/telepath

我想在每个客户上显示这个发布的数据。 我在文档上尽我所能,但这对我来说并不容易。

这是我的脚本:

from quart import Quart, render_template, websocket
from functools import partial, wraps
from quart import request, redirect, url_for, copy_current_websocket_context
import asyncio

app = Quart(__name__)

connected_websockets = set()

def collect_websocket(func):
    @wraps(func)
    async def wrapper(*args, **kwargs):
        global connected_websockets
        queue = asyncio.Queue()
        connected_websockets.add(queue)
        try:
            return await func(queue, *args, **kwargs)
        finally:
            connected_websockets.remove(queue)
    return wrapper

async def broadcast(message):
    for queue in connected_websockets:
        await queue.put(message)

@app.route('/')
async def index():
    return await render_template('index.html')


@app.websocket('/ws')
@collect_websocket
async def ws(queue):
    print("$ $ $",queue)
    while True:
        data = await websocket.receive()
        print("\n {}".format(data))
        await websocket.send(f"echo {data}")



@app.route('/telepath', methods=['POST'])
async def telepath():
    global connected_websockets    
    data = await request.get_json()
    for queue in connected_websockets:
        await queue.put(data["key1"])
    return "\n Request Processed.\n"



if __name__ == '__main__':
    app.run(port=5000)

和模板:

<!doctype html>
<html>
  <head>
    <title>My TEST</title>
  </head>
  <body>
    <input type="text" id="message">
    <button>Send</button>
    <ul></ul>
    <script type="text/javascript">
      var ws = new WebSocket('ws://' + document.domain + ':' + location.port + '/ws');
      ws.onmessage = function (event) {
        var messages_dom = document.getElementsByTagName('ul')[0];
        var message_dom = document.createElement('li');
        var content_dom = document.createTextNode('Received: ' + event.data);
        message_dom.appendChild(content_dom);
        messages_dom.appendChild(message_dom);
      };

      var button = document.getElementsByTagName('button')[0];
      button.onclick = function() {
        var content = document.getElementsByTagName('input')[0].value;
        ws.send(content);
      };


    document.addEventListener('DOMContentLoaded', function() {
    var es = new EventSource('/telepath');
    es.onmessage = function (event) {
        var messages_dom = document.getElementsByTagName('ul')[0];
        var message_dom = document.createElement('li');
        var content_dom = document.createTextNode('Received: ' + event.data);
        message_dom.appendChild(content_dom);
        messages_dom.appendChild(message_dom);
      };

    
    });


    let socket = new WebSocket("ws://localhost:5000/ws");

    socket.onmessage = function(event) {
        alert(`Data received: ${event.data}`);
        
    };

    
    
    </script>
  </body>
</html>

我的最终目标是身份验证,并针对谁 可以接收来自服务器的私信。

无法在 mozilla 或 chrome 客户端上通过 curl 传输发布的数据。

【问题讨论】:

    标签: python websocket messaging quart


    【解决方案1】:

    在您的collect_websocket 装饰器中,您将queue 参数传递给websocket 处理程序(return await func(queue, *args, **kwargs)),而您的websocket 处理程序不接受任何参数(async def ws())。这会导致您看到的错误。

    看起来您的 ws_v2 websocket 处理程序已设置为与 collect_websocket 装饰器 (async def ws_v2(queue)) 一起使用,所以我认为您可以切换到使用它并重写 Telepath,

    @app.route('/telepath', methods=['POST'])
    async def telepath():
        global connected_websockets    
        data = await request.get_json()
        for queue in connected_websockets:
            await queue.put(data["key1"])
    return {}
    

    请注意,您不需要在 /telepath 路由中创建任何队列,因为这是由您的 collect_websocket 装饰器完成的,而且您需要为每个 websocket 连接创建一个队列。您也不需要等待 ws_v2 处理程序,只要有新的 websocket 连接,就会调用它。

    对于身份验证,我建议您从Quart-Auth 开始(我是该库的作者)。


    编辑:根据要求编辑完整代码,

    import asyncio
    from functools import partial, wraps
    
    from quart import (
        copy_current_websocket_context, Quart, render_template, 
        request, websocket
    )
    
    app = Quart(__name__)
    
    connected_websockets = set()
    
    def collect_websocket(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            global connected_websockets
            queue = asyncio.Queue()
            connected_websockets.add(queue)
            try:
                return await func(queue, *args, **kwargs)
            finally:
                connected_websockets.remove(queue)
        return wrapper
    
    async def broadcast(message):
        global connected_websockets 
        for queue in connected_websockets:
            await queue.put(message)
    
    @app.route('/')
    async def index():
        return await render_template('index.html')
    
    @app.websocket('/ws')
    @collect_websocket
    async def ws(queue):
        await websocket.accept()
        while True:
            data = await queue.get()
            await websocket.send_json(data)
    
    @app.route('/telepath', methods=['POST'])
    async def telepath():   
        data = await request.get_json()
        await broadcast(data)
        return {}
    
    if __name__ == '__main__':
        app.run(port=5000)
    

    和模板,

    <!doctype html>
    <html>
      <head>
        <title>My TEST</title>
      </head>
      <body>
        <ul></ul>
        <script type="text/javascript">
          var ws = new WebSocket('ws://' + document.domain + ':' + location.port + '/ws');
          ws.onmessage = function (event) {
            const messagesDOM = document.getElementsByTagName('ul')[0];
            const messageDOM = document.createElement('li');
            const message = JSON.parse(event.data).message;
            const contentDOM = document.createTextNode('Received: ' + message);
            messageDOM.appendChild(contentDOM);
            messagesDOM.appendChild(messageDOM);
          };
        </script>
      </body>
    </html>
    

    然后使用 curl,

    curl -H "content-type: application/json" -d '{"message": "Hello"}' localhost:5000/telepath
    

    请注意,服务器会将其接收到的所有 JSON 数据发送给客户端,但客户端仅使用 message 键。

    【讨论】:

    • 能否提供完整的详细工作示例,我提供 100 分赏金 ;-)
    • 是的,我刚刚添加了完整的详细工作示例。它允许您发布到 /telepath 路由,然后发送到连接的客户端。
    猜你喜欢
    • 1970-01-01
    • 2018-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-23
    • 2020-10-30
    相关资源
    最近更新 更多