django中的Websocket通知



我正在Django项目中实现web套接字通知,并且在向用户传递他们当前拥有的未读通知数量时遇到了问题。

我对这个问题的解决方案是,一旦用户连接到web套接字,就简单地将通知模型类中的所有对象作为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"]))

javascript:

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,选项卡就可以只显示每个通知一次。

它可以是基本的,就像NotificationConsumer类中的一个新索引变量(每次在send_notification中递增(,以及javascript中的全局变量(存储处理的最后一个索引(,类似

var last_index = 0;
...
socket.onmessage = function(e){
document.getElementById("no-alerts").innerHTML = "";
console.log('message recieved')
const obj = JSON.parse(e.data);
const object = JSON.parse(obj);
if (last_index < object.index) {
last_index = object.index;
//process message...
}
...

一个潜在的(但不太可能的(陷阱是,如果你的通知被发送或接收不正常,这将导致一些通知被跳过。我无法推测这是如何通过websocket发生的,但如果这是一个问题,您需要在javascript端保存一个足够大的最后处理的消息数组,以覆盖潜在的序列中断。在这一点上,这只是猜测,但如果你觉得这适用于你,请随时发表评论。

最新更新