Django通道+在发布请求后发送websocket消息



我的应用程序有问题。我的django通道和websocket工作得非常好,当我从JS(在渲染的html中(发送消息时,消息将进入websocket,然后(异步(发送到数据库。但是,当我尝试在POST请求Render之前发送消息时,它会抛出一个错误。

#here everything works fine:
def room(request, room_name):
messages = message.objects.all()
texts = []

for i in messages:
texts.append(i.text)

last_lines = texts[-20:]

vars = {
"room_name": room_name,
"messages": last_lines,
}
print()
if request.method == "POST":
vars["post_d"] = request.POST.get("desc")
print(vars["post_d"])
# ws = create_connection("ws://127.0.0.1:8000/ws/chat/loobby/")
# time.sleep(2)
# ws.send(json.dumps({"message": message}))
return render(request, "chat/room.html", vars)
return render(request, "chat/room.html", vars)
#=======================================================
System check identified no issues (0 silenced).
July 12, 2021 - 08:26:23
Django version 3.1.3, using settings 'onionChat.settings'
Starting ASGI/Channels version 3.0.3 development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
Post request from c# console app
HTTP POST /chat/loobby/ 200 [0.10, 127.0.0.1:3261]

我的test.py文件发送python-websocket消息(也运行良好(,更改显示在web浏览器的数据库和websocket中。

import json
import time
import asyncio
from websocket import create_connection
async def send(message):
ws = create_connection("ws://127.0.0.1:8000/ws/chat/loobby/")
time.sleep(2)
ws.send(json.dumps({"message": message}))
print("here")
if __name__ == "__main__":
asyncio.run(send("nothing"))
#==================================================================
System check identified no issues (0 silenced).
July 12, 2021 - 08:29:48
Django version 3.1.3, using settings 'onionChat.settings'
Starting ASGI/Channels version 3.0.3 development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
WebSocket HANDSHAKING /ws/chat/loobby/ [127.0.0.1:1032]
WebSocket CONNECT /ws/chat/loobby/ [127.0.0.1:1032]
WebSocket DISCONNECT /ws/chat/loobby/ [127.0.0.1:1032]
added message to db

但当我试图在返回渲染后发送websocket消息AND时,它会抛出一个错误

def room(request, room_name):
messages = message.objects.all()
texts = []
for i in messages:
texts.append(i.text)
last_lines = texts[-20:]
vars = {
"room_name": room_name,
"messages": last_lines,
}
print()
if request.method == "POST":
vars["post_d"] = request.POST.get("desc")
print(vars["post_d"])
ws = create_connection("ws://127.0.0.1:8000/ws/chat/loobby/")
time.sleep(2) 
ws.send(json.dumps({"message": message}))
return render(request, "chat/room.html", vars)
#==================================================================
System check identified no issues (0 silenced).
July 12, 2021 - 08:34:51
Django version 3.1.3, using settings 'onionChat.settings'
Starting ASGI/Channels version 3.0.3 development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
Post request from c# console app
WebSocket HANDSHAKING /ws/chat/loobby/ [127.0.0.1:30427]
WebSocket DISCONNECT /ws/chat/loobby/ [127.0.0.1:30427]
Internal Server Error: /chat/loobby/
Traceback (most recent call last):
File "C:Program FilesPython39libsite-packagesasgirefsync.py", line 339, in thread_handler
raise exc_info[1]
File "C:Program FilesPython39libsite-packagesdjangocorehandlersexception.py", line 38, in inner
response = await get_response(request)
File "C:Program FilesPython39libsite-packagesdjangocorehandlersbase.py", line 231, in _get_response_async
response = await wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:Program FilesPython39libsite-packagesasgirefsync.py", line 304, in __call__
ret = await asyncio.wait_for(future, timeout=None)
File "C:Program FilesPython39libasynciotasks.py", line 442, in wait_for
return await fut
File "C:Program FilesPython39libconcurrentfuturesthread.py", line 52, in run
result = self.fn(*self.args, **self.kwargs)
File "C:Program FilesPython39libsite-packagesasgirefsync.py", line 343, in thread_handler
return func(*args, **kwargs)
File "C:UsersАлексейDesktopdevOnionChatonionChatchatviews.py", line 48, in room
ws = create_connection("ws://127.0.0.1:8000/ws/chat/loobby/")
File "C:UsersАлексейAppDataRoamingPythonPython39site-packageswebsocket_core.py", line 595, in create_connection
websock.connect(url, **options)
File "C:UsersАлексейAppDataRoamingPythonPython39site-packageswebsocket_core.py", line 252, in connect
self.handshake_response = handshake(self.sock, *addrs, **options)
File "C:UsersАлексейAppDataRoamingPythonPython39site-packageswebsocket_handshake.py", line 59, in handshake
status, resp = _get_resp_headers(sock)
File "C:UsersАлексейAppDataRoamingPythonPython39site-packageswebsocket_handshake.py", line 143, in _get_resp_headers
status, resp_headers, status_message = read_headers(sock)
File "C:UsersАлексейAppDataRoamingPythonPython39site-packageswebsocket_http.py", line 300, in read_headers
line = recv_line(sock)
File "C:UsersАлексейAppDataRoamingPythonPython39site-packageswebsocket_socket.py", line 136, in recv_line
c = recv(sock, 1)
File "C:UsersАлексейAppDataRoamingPythonPython39site-packageswebsocket_socket.py", line 115, in recv
bytes_ = _recv()
File "C:UsersАлексейAppDataRoamingPythonPython39site-packageswebsocket_socket.py", line 92, in _recv
return sock.recv(bufsize)
ConnectionResetError: [WinError 10054] Удаленный хост принудительно разорвал существующее подключение
HTTP POST /chat/loobby/ 500 [4.97, 127.0.0.1:30426]

和我的c#代码,但我不认为问题在这里

static void post_command(string command)
{
using (var client = new WebClient())
{
client.Timeout = 600 * 60 * 1000;

client.Headers["User-Agent"] = "Mozilla/5.0";
var values = new NameValueCollection();
values["desc"] = $"{command}"; 
client.UploadValues(link, values);
//var responseString = Encoding.Default.GetString(response);
//Console.Write(responseString);
}
}

我知道这是一个相当古老的问题,尽管我现在面临着同样的问题。似乎不可能从已经提供此类连接的应用程序中打开web套接字连接。这就是test.py工作的原因,因为它在Django应用程序之外。

因此,我想出了一个解决方案,从当前打开的套接字中提取相关通道:

视图.py

from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
def room(request, room_name):
# your logic...
if request.method == "POST":
vars["post_d"] = request.POST.get("desc")
print(vars["post_d"])
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
f'chat_{room_name}',
{
'type': 'receive',
'message': message
}
)

假设在路由.py中您有:

from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r'ws/chat/(?P<room_name>w+)/$', consumers.ChatConsumer.as_asgi()),
]

consumer.py中,您必须相应地匹配receive方法(注意type='receive'(和channel名称(在您的示例中是lobal(

from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = f'chat_{self.room_name}'
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def receive(self, text_data=None, type='receive', **kwargs):
if isinstance(text_data, dict):
text_data_json = text_data
else:
text_data_json = json.loads(text_data)
# all other logic on handling the message...

最新更新