无法通过 group_send 向 Django 频道发送消息

Cant send a message to a Django channel via group_send

我想使用 Django Channels 通过频道发送消息。我就是这样做的。

我先创建一个消费者。我能够回显收到的消息。但是,无法将消息发送到特定的 channel/group。

class Consumer(AsyncJsonWebsocketConsumer):
    """Consumer."""

    def _get_connection_id(self):
        return ''.join(e for e in self.channel_name if e.isalnum())

    async def connect(self):
        scope = self.scope
        user_id = str(scope['user'].user_id)
        connection_id = self._get_connection_id()
        # Adding connection to DB.
        obj = UserConnection.add(connection_id=connection_id, user_id=user_id)

        # Accept the connection
        await self.accept()

        # Adding current to group.
        await self.channel_layer.group_add(
            user_id,
            connection_id,
        )

    async def disconnect(self, close_code):
        """Remove the connection and decrement connection_count in DB."""
        connection_id = self._get_connection_id()
        user_id = str(self.scope['user'].user_id)

        UserConnection.drop(connection_id=connection_id)

        # Dropping from group.
        await self.channel_layer.group_discard(
            user_id,
            connection_id,
        )

    async def receive_json(self, data, **kwargs):
        """Receive messages over socket."""
        resp = data
        # I'm able to echo back the received message after some processing.
        await self.send(json.dumps(resp, default=str))


# This does not works.
def send_to_connection(connection_id, data):
    """Send the data to the connected socket id."""
    return get_channel_layer().group_send(connection_id, data)

现在当我尝试发送消息时,连接的套接字没有收到消息。

>>> connection_id = UserConnection.objects.get(user_id=user_id).connection_id
>>> send_to_connection(connection_id, {'a':1})
# returns <coroutine object RedisChannelLayer.group_send at 0x109576d40>

代码中有什么问题?

对通道层的工作原理存在一些误解。让我试着把它弄清楚。当客户端连接到 Channels 服务器时,将为该客户端创建一个消费者实例或通道。如果您将频道添加到组中,Django Channels 会将该信息存储在频道层中。如果你想向一个组中的所有客户端发送消息,首先你通过通道层将它发送到他们的connections/channels,然后通道将它向下发送到连接的客户端。

因此,在您的情况下,当您调用 group_send 时,它不会将消息发送到客户端应用程序,因为它没有关于 websocket 连接的信息,而是发送到客户端应用程序的使用者实例。然后该消费者实例需要获取消息并将其转发给客户端。

按照文档中的示例,这是您需要做的:

    async def receive_json(self, data, **kwargs):
        """Receive messages over socket."""
        resp = data
        # I'm able to echo back the received message after some processing.
        await self.send(json.dumps(resp, default=str))
   
   # catches group messages from channel layer and forwards downstream to client 
   async def forward_group_message(self, event):
        await self.send(json.dumps(event['data'], default=str))

# Sends message to all channels in a group cia the channel layer
def send_to_connection(connection_id, data):
    """Send the data to the connected socket id."""
    return get_channel_layer().group_send(
        connection_id, 
        {"type": "forward_group_message", "data": data}
    )

注意发送到通道层的事件中的type键。这就是 Django Channel 知道将通道层事件路由到哪个 method/handler 消费者的方式。您还可以使用文档中使用的点符号,Django Channels 仍会找到处理程序。所以你可以使用 "type": "forward.group.message"