django - 无法通过 group_send 向 Django 频道发送消息
问题描述
我想使用 Django 频道通过频道发送消息。这就是我正在做的。
我首先创建一个消费者。我能够回显收到的消息。但是,无法将消息发送到特定的频道/组。
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>
代码中有什么问题?
解决方案
对 Channel 层的工作方式存在一些误解。让我试着把它弄清楚。当客户端连接到 Channels 服务器时,会为该客户端创建一个消费者实例或通道。如果将频道添加到组中,Django 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 知道消费者的哪个方法/处理程序将通道层事件路由到的方式。您还可以使用文档中使用的点表示法,Django Channels 仍然会找到处理程序。所以你可以使用"type": "forward.group.message"
推荐阅读
- maven - 春天:java.lang.ClassNotFoundException:org.springframework.boot.SpringApplication 未找到
- javascript - 添加对象的项目长度
- python - 用 Django 查询不起作用
- javascript - 将多个数据行传递到下一页的表格
- c++ - 在中断信号上实现服务器停止操作的最佳方法是什么?
- node.js - Express.js、Passport.js、cookie-session、注销不会删除 cookie
- c++ - 带有纯虚函数的模板类的 C++ 实现
- python - 如何将日期时间从某个时区转换为 UTC?django 日期时间字段
- android - 由于 appcompat 无法渲染
- ios - InAppSettingsKit - 如何以编程方式刷新标题/值?