這次要藉由websocket做出網站實時的線上人數,關於django的websocket設定就不贅述了,網路上已經有相當多的資源,就寫一些重點當筆記 ~
一開始最重要的就是要了解WebSocket支援的四個訊息:onopen,onmessage,onclose和onerror,然後根據你的需求去調用:
<body>
<h1 id="app">{{ text }}</h1>
<script>
var socket = new WebSocket('ws://' + window.location.host + '/ws/online_number/');
socket.onopen = function(e){
console.log ("open", e);
}
socket.onerror = function(e){
console.log ("error", e)
}
socket.onmessage = function(e){
var data = JSON.parse(e.data);
var message = data['message'];
console.log("message",e);
document.querySelector('#app').innerText = message;
}
</script>
</body>
我的想法很簡單,只要使用者一進入網站就都放在同一個group裡面,如下圖的灰底部分,反之使用者一離開網站,他的資料就不會再存在於redis,然後只要再去抓取redis裡的數目就會知道實時的人數了,
那要怎麼實時的在網站顯示線上使用人數呢?這邊有個重點就是channel_layer.group_send,首先要知道傳送到哪個group(這邊room_group_name是users),再來就是要傳送到前端的資料(這邊一定要寫成字典的形式),type為指定訊息處理的函式(number),這邊就是處理成傳個json,message為從redis得出的人數。
用redis_connect.zcard得出在group裡的數量即代表線上人數。
小結:connect跟disconnect時都要做差不多的操作來反映出實時的人數。
class NumberOfOnline(AsyncWebsocketConsumer):
db = Redis(host='127.0.0.1', port=8000, db=0)
async def connect(self):
await self.accept()
self.room_group_name = 'users'
await self.channel_layer.group_add(self.room_group_name, self.channel_name)
redis_connect = get_redis_connection('default')
online_number = str(redis_connect.zcard("asgi:group:users"))
print('線上人數', online_number)
await self.channel_layer.group_send(self.room_group_name,{'type':'number', 'message':online_number})
async def disconnect(self, close_code):
await self.channel_layer.group_discard('users', self.channel_name)
user = self.scope['user']
redis_connect = get_redis_connection('default')
online_number = str(redis_connect.zcard("asgi:group:users"))
print('線上人數', online_number)
await self.channel_layer.group_send(self.room_group_name,{'type':'number', 'message':online_number})
async def number(self, event):
message = event['message']
await self.send(text_data=json.dumps({
'message': message
}))
到目前為止只在本機測試,之後部署的話要開始研究asgi server的部分,django目前有提供daphne、Hypercorn、Uvicorn。可能會先試試daphne,但官方文件提供的資訊就只有下圖這樣:
感覺會遇到的坑不少...總之就先來try看看吧 ~