问题描述
我以这种方式进行了编辑:
我的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传输已发布的数据。
解决方法
在您的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,**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
密钥。