You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 03:15:50