思路
- channels 提供了在Consumer外部调用发送信息的方式,channels中每个客户端连接时会生成一个channel_name, 而channel_name对应了是哪个客户端, group_name对应的是用户组。
- 那么可以通过把channel_name和group_name的值保存下来,在http请求的接口中进行外部调用。
实例
例子是继承AsyncJsonWebsocketConsumer
的, 所以是异步的,可接受发送json
格式的数据, 代码如下。
from channels.db import database_sync_to_async
from channels.generic.websocket import AsyncJsonWebsocketConsumer
@database_sync_to_async
def save_channel_name(key, channel_name, group_name):
"""
:param key:
:param channel_name:
:param group_name:
:return:
"""
# 这里可以通过redis或数据库将对于的channel_name, group_name保存下来。
pass
class WbConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
# 这
key = self.scope['url_route']['kwargs']['peronId'] # 在websocket链接的时候获取到用户标识,可以从jwt信息中获取,可以在路由中获取某个参数作为标识
group_name = 'group_' + key
await save_channel_name(key, self.channel_name)
# 当前频道添加进频道组
await self.channel_layer.group_add(group_name, self.channel_layer)
await self.accept()
async def disconnect(self, code):
print('关闭连接')
async def receive_json(self, content, **kwargs):
print('接收数据:', content)
await self.send_json(content={
'msg': '收到收到over!'
})
async def test_message(self, event):
"""
发送测试数据
:param event:
:return:
"""
message = event['message']
await self.send_json(message)
首先在connect
方法中, 可以拿到客户端发起连接的请求路由参数,请求头等,如使用jwt
认证的话,解析header
里面的信息可以拿到用户ID, 以用户ID作为键将channel_name
和group_name
保存起来。
- http发起请求的接口中,可以定义:
from asgiref.sync import async_to_sync
channel_name = 'xxxx' # 获取到之前保存的对应的channel_name
group_name = 'xxxxx' # 获取到之前保存的对应的group_name
# 同步发送数据到组
async_to_sync(channel_layer.group_send)(group_name, {"type": "test.message"})
# 同步方式发送数据到对应websocket连接
async_to_sync(channel_layer.send)(channel_name, {"type": "test.message"})