Django Channels向指定用户组发送WebSocket消息失败问题排查
问题描述
访问“等候室”页面的用户连接WebSocket后,会订阅以自身user_id命名的分组。当用户匹配到其他用户时(比如User1匹配到User2),User1会把User2的信息和room_id发送给服务器,服务器需要向User2对应的分组推送消息,但实际User2收不到消息,终端能看到日志但报错。
提供的consumers.py代码
class PracticeConsumer(AsyncConsumer): username_id = None async def websocket_connect(self, event): username = self.scope['user'] username_id = str(await self.get_user(username)) group_name = username_id await self.channel_layer.group_add( '{}'.format(group_name), self.channel_name ) await self.send({ "type": "websocket.accept" }) async def websocket_receive(self, event): received = event["text"] invite_data = received.split() matched_user = invite_data[0] username = invite_data[2] user_id = str(await self.get_user(matched_user)) my_response = { "message": "!!!!the websocket is sending this back!!!!" } sleep(1) await self.channel_layer.group_send( '{}'.format(user_id), { "type": "send.message", "message": json.dumps(my_response), "username": username }) ... async def send_message(self, event): message = event['message'] await self.send({ 'message': message }) @database_sync_to_async def get_user(self, user_id): try: return User.objects.get(username=user_id).pk except User.DoesNotExist: return AnonymousUser()
报错信息(翻译后)
INFO 2022-09-26 10:09:43,129: WebSocket CONNECT /connect/testing/ [127.0.0.1:56653] INFO 2022-09-26 10:09:44,239: 发送消息到presenter{"message": "!!!!the websocket is sending this back!!!!"} INFO 2022-09-26 10:09:44,240: 发送消息到presenter{"message": "!!!!the websocket is sending this back!!!!"} 应用内部异常: 'type' 回溯(最近的调用最后): 文件 "C:\Users\15512\Desktop\django-project\peerplatform\signup\middleware.py", line 45, in __call__ return await super().__call__(scope, receive, send) ... 文件 "C:\Users\15512\anaconda3\lib\site-packages\channels\consumer.py", 文件 "C:\Users\15512\Desktop\django-project\peerplatform\signup\consumers.py", line 76, in send_message await self.send({ 文件 "C:\Users\15512\anaconda3\lib\site-packages\channels\consumer.py", line 81, in send await self.base_send(message) 文件 "C:\Users\15512\anaconda3\lib\site-packages\channels\sessions.py", line 186, in send message["type"] in self.save_message_types
修复方案
1. 修正WebSocket消息发送格式
报错核心原因是send_message方法里调用self.send()时,消息缺少必填的type字段,并且WebSocket消息内容需要放在text字段中。修改后的代码:
async def send_message(self, event): message = event['message'] await self.send({ "type": "websocket.send", # 指定消息类型为WebSocket发送 "text": message # 消息内容存入text字段 })
2. 替换同步sleep为异步方法
原代码中的sleep(1)是同步阻塞方法,会卡住整个异步事件循环,换成异步的asyncio.sleep,记得先导入asyncio:
import asyncio # 在websocket_receive方法里替换原sleep(1) await asyncio.sleep(1)
3. 修正类变量作用域
websocket_connect里的username_id是局部变量,没有赋值给类属性,规范写法应该改为:
self.username_id = str(await self.get_user(username))
4. 处理用户不存在的返回值
get_user方法中,用户不存在时返回AnonymousUser(),转成字符串后会得到"AnonymousUser",可能导致无效分组名,建议改为返回字符串标识:
@database_sync_to_async def get_user(self, user_id): try: return User.objects.get(username=user_id).pk except User.DoesNotExist: return "anonymous" # 用字符串标识匿名用户
内容的提问来源于stack exchange,提问作者Emm
相关产品推荐
相关产品推荐

