无法通过 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"
我想使用 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"