如何使用 django 通道和 websockets 从服务器的任何位置向客户端发送事件
How to send event to client from any place of server using django channels and websockets
现在我正在使用 django 和 angular 构建一个网站,我想在客户端和服务器之间添加 websocket 通信。
我按照 django 频道文档的说明进行操作。( https://channels.readthedocs.io/ )
我想从 django 服务器代码的任何地方发送任何事件。但是当多个用户通过套接字连接时,服务器发送的数据总是发送给最后一个连接的用户。
这就是我所做的。
首先在 consumers.py 中,我如下定义了 ChatConsumer class 并添加了一个名为“tweet_send”的新处理程序函数
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
...
# here's what I added a new tweet send handler
async def tweet_send(self, event):
content = event['content']
content["group_name"] = self.room_group_name
# Send message to WebSocket
await self.send(text_data=json.dumps({
"type": "MESSAGE",
"data": content
}))
在 django 服务器端的某个地方(在 serializers.py 中),当创建新的推文时,我使用 django.channel_layer
向所有用户发送新的推文数据
...
def create(self, validated_data):
...
new_tweet.save()
# send message via channels
channel_layer = get_channel_layer()
all_users = list(Member.objects.filter(is_active = True).values_list('id', flat = True))
for user_id in all_users:
async_to_sync(channel_layer.group_send)(
"chat_{}".format(user_id), # this is the group name of group name of individual users.
{ "type": "chat_message", "message": "tweet created" }
)
并且在 Angular websocket 服务中
init(userID: number): void{
if(this.ws){
this.ws.close();
}
this.ws = new WebSocket(`${environment.WEBSOCKET_URL}/chat/${userID}/`);
this.ws.onopen = () => {
this.currentWebSocketSubject.subscribe(data => {
if (data) {
this.ws?.send(JSON.stringify(data));
}
});
};
this.ws.onmessage = (event) => {
console.log("message arrived");
console.log(event);
if (event.data) {
const tempData: WS = JSON.parse(event.data) as WS;
switch (tempData.type) {
case 'MESSAGE':
console.log("message arrived");
console.log(tempData);
if (tempData.data) {
this.unreadMessages++;
this.messageSubject.next(tempData);
}
break;
}
}
};
}
我测试这些代码的时候,用了两个客户端,两个客户端登录,通过websockets成功连接到django服务器。
当我创建推文时,django 服务器使用 channel_layer.group_send 函数向每个频道发送事件,而在 ChatConsumer class 中添加的“tweet_send”函数将事件发送给用户。
这些事件分别针对不同的用户。
但是它们都被发送给最后一个连接到 websocket 的用户。
我不知道为什么。请帮助我。
我想你一定是在使用 channels 3.0.0 并且出现了这个错误。我建议您将频道版本升级到 3.0.1 或 3.0.2。
然后错误就会消失。
现在我正在使用 django 和 angular 构建一个网站,我想在客户端和服务器之间添加 websocket 通信。 我按照 django 频道文档的说明进行操作。( https://channels.readthedocs.io/ ) 我想从 django 服务器代码的任何地方发送任何事件。但是当多个用户通过套接字连接时,服务器发送的数据总是发送给最后一个连接的用户。 这就是我所做的。 首先在 consumers.py 中,我如下定义了 ChatConsumer class 并添加了一个名为“tweet_send”的新处理程序函数
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
...
# here's what I added a new tweet send handler
async def tweet_send(self, event):
content = event['content']
content["group_name"] = self.room_group_name
# Send message to WebSocket
await self.send(text_data=json.dumps({
"type": "MESSAGE",
"data": content
}))
在 django 服务器端的某个地方(在 serializers.py 中),当创建新的推文时,我使用 django.channel_layer
向所有用户发送新的推文数据...
def create(self, validated_data):
...
new_tweet.save()
# send message via channels
channel_layer = get_channel_layer()
all_users = list(Member.objects.filter(is_active = True).values_list('id', flat = True))
for user_id in all_users:
async_to_sync(channel_layer.group_send)(
"chat_{}".format(user_id), # this is the group name of group name of individual users.
{ "type": "chat_message", "message": "tweet created" }
)
并且在 Angular websocket 服务中
init(userID: number): void{
if(this.ws){
this.ws.close();
}
this.ws = new WebSocket(`${environment.WEBSOCKET_URL}/chat/${userID}/`);
this.ws.onopen = () => {
this.currentWebSocketSubject.subscribe(data => {
if (data) {
this.ws?.send(JSON.stringify(data));
}
});
};
this.ws.onmessage = (event) => {
console.log("message arrived");
console.log(event);
if (event.data) {
const tempData: WS = JSON.parse(event.data) as WS;
switch (tempData.type) {
case 'MESSAGE':
console.log("message arrived");
console.log(tempData);
if (tempData.data) {
this.unreadMessages++;
this.messageSubject.next(tempData);
}
break;
}
}
};
}
我测试这些代码的时候,用了两个客户端,两个客户端登录,通过websockets成功连接到django服务器。 当我创建推文时,django 服务器使用 channel_layer.group_send 函数向每个频道发送事件,而在 ChatConsumer class 中添加的“tweet_send”函数将事件发送给用户。 这些事件分别针对不同的用户。 但是它们都被发送给最后一个连接到 websocket 的用户。 我不知道为什么。请帮助我。
我想你一定是在使用 channels 3.0.0 并且出现了这个错误。我建议您将频道版本升级到 3.0.1 或 3.0.2。 然后错误就会消失。