我在Django项目中实现了Web Socket通知,但是在向用户传递他们当前拥有的未读通知数量时遇到了麻烦。
我对这个问题的解决方案是,一旦用户连接到Web Socket字,就将通知模型类中的所有对象作为Web套接字本身中的消息发送给用户,这最初是有效的,但是如果存在多于一个打开的标签,则中断,因为每个新的标签再次连接到Web Socket,这又将web套接字消息再次发送到登录到该用户的任何其他打开的标签。以相同通知的重复结束。
我所需要的是一种方法显示所有的通知在每一页时,它是加载。最好不发送它通过上下文的一个视图。
consumers.py:
@database_sync_to_async
def create_notification(notification):
"""
function to create a notification.
:param notification: notification in json format to create notification object
"""
user = User.objects.get(username=notification["target"])
NotificationsModel.objects.create(
target=user,
sender=notification["sender"],
alertType=notification["alertType"],
title=notification["title"],
message=notification["message"],
)
class NotificationConsumer(AsyncWebsocketConsumer):
async def websocket_connect(self, event: dict) -> None:
if self.scope["user"].is_anonymous:
await self.close()
else:
self.group_code = self.scope["url_route"]["kwargs"]["group_code"]
await self.channel_layer.group_add(self.group_code, self.channel_name)
await self.accept()
# Since removed the send notifications from here as they encountered the problem described above
async def websocket_receive(self, event: dict) -> None:
message = event["text"] # anything sent to websocket_receive has {"type": "websocket.receive", "text": "foo"}
type_of_handler = json.loads(message)
type_of_handler = type_of_handler["type"]
await self.channel_layer.group_send(self.group_code, {"type": type_of_handler, "message": message})
async def websocket_disconnect(self, event: dict) -> None:
await self.channel_layer.group_discard(self.group_code, self.channel_name)
await self.close()
# custom message handlers called based on "type" of message sent
async def send_notification(self, event: dict) -> None:
await self.send(json.dumps({"type": "websocket.send", "message": event}))
async def notify_and_create(self, event: dict) -> None:
message = json.loads(event["message"])
await create_notification(message["notification"])
notification = json.dumps(message["notification"])
await self.channel_layer.group_send(
str(message["notification"]["target_id"]), {"type": "notification", "message": notification}
)
async def notification(self, event: dict) -> None:
await self.send(text_data=json.dumps(event["message"]))
浏览器:
try{
var groupCode = document.getElementById("user");
var user = groupCode.getAttribute('user')
}catch(err){
throw Error('notifications not active (do not worry about this error)')
}
var loc = window.location;
var wsStart = "ws://";
if (loc.protocol == "https:"){
wsStart = "wss://";
}
var webSocketEndpoint = wsStart + loc.host + '/ws/notifications/' + user + '/'; // ws : wss // Websocket URL, Same on as mentioned in the routing.py
var socket = new WebSocket(webSocketEndpoint) // Creating a new Web Socket Connection
console.log('CONNECTED TO: ', webSocketEndpoint)
var counter = 0;
// Socket On receive message Functionality
socket.onmessage = function(e){
document.getElementById("no-alerts").innerHTML = "";
console.log('message recieved')
const obj = JSON.parse(e.data);
const object = JSON.parse(obj);
console.log(object)
var toastElList = [].slice.call(document.querySelectorAll('.toast'))
var toastList = toastElList.map(function (toastEl) {
return new bootstrap.Toast(toastEl)
})
counter = counter + 1;
document.getElementById("badge-counter").innerHTML = counter;
if (counter < 4) {
// stuff to show notifications in html
}
}
// Socket Connect Functionality
socket.onopen = function(e){
document.getElementById("no-alerts").append("No New Alerts!");
console.log('open', e)
}
// Socket Error Functionality
socket.onerror = function(e){
console.log('error', e)
}
// Socket close Functionality
socket.onclose = function(e){
console.log('closed', e)
}
有什么好主意能给我指明方向吗?
1条答案
按热度按时间rkue9o1l1#
我在这里重点介绍了最简单的可能解决方案,但我的答案存在一个潜在的缺陷,我将在最后描述,因此您需要评估这对于您的用例是否可管理。
假设您希望保持当前使用的“批量发送”方法的简单性,您可以通过向通知添加索引(一个数字),并在每个选项卡中跟踪最后处理的通知索引,仅对具有较高索引值的通知做出React,从而通过最小的修改来解决此问题。
通过简单地将后端发送的每个不同通知的索引增加1,您的选项卡可以只显示每个通知一次。
它可以像
NotificationConsumer
类中的一个新索引变量(每次在send_notification
中递增)和javascript中的一个全局变量(用于存储上次处理的索引)一样基本,类似于一个潜在(但不太可能)陷阱是如果你的通知被无序发送或接收,这将导致一些通知被跳过。我不能推测这是如何通过WebSocket发生的,但如果这是一个问题,你需要在javascript端保存一个足够大的最后处理的消息数组来覆盖潜在的序列中断。这是目前的推测,但如果你觉得这对你适用,请随意发表评论。