Số người trực tuyến và người xem
Hiện số người đang trực tuyến hoặc đang xem, đếm người dùng duy nhất bằng presence, và đọc số người mỗi phòng từ máy chủ bằng HTTP API và webhook.
"1.284 người đang trực tuyến", "38 người đang xem", "Phòng đã đầy": một con số người thật, cập nhật liên tục, khiến sản phẩm trông sôi động, và cũng chính con số đó cho đội của bạn biết phòng nào đang đông, khi nào cần thêm người điều phối và đỉnh buổi tối cao đến đâu. Bạn không cần tự đếm kết nối. Hibira đã biết ai đang đăng ký mỗi kênh, và giao thức Pusher cho bạn bốn cách để hỏi.
Người dùng của bạn nhận được gì
- Con số "đang trực tuyến" hoặc "đang xem" thay đổi khi có người vào và ra.
- Một hàng ảnh đại diện kèm "+120 người khác", người mở hai tab chỉ tính một lần.
- Phòng báo "đã đầy" trước khi có ai cố vào.
- Cho đội của bạn: một trang quản trị với các phòng đông nhất, và lịch sử các đỉnh.

Xây dựng bằng
- Số người đăng ký (
pusher:subscription_count) để có con số trong trình duyệt trên kênh công khai và kênh riêng tư. - Kênh presence (
presence-) để đếm người dùng duy nhất, và kênh presence lớn (presence-large-) cho tới 100.000 thành viên. - HTTP API (
GET /channels) để máy chủ của bạn đọc con số bất cứ lúc nào. - Webhook (
member_added,member_removed,subscription_count) để được báo khi con số thay đổi, nhờ đó bạn lưu được lịch sử.
Trong trình duyệt
pusher:subscription_countMáy chủ của bạn hỏi
GET /channels?info=user_countMáy chủ của bạn được báo
member_addedĐếm kết nối hay đếm người?
Đây là hai con số khác nhau, nên chọn có chủ đích:
subscription_countđếm kết nối. Một người mở ba tab được tính ba lần. Nó hoạt động trên kênh công khai và riêng tư mà không cần đăng nhập, nên hợp với bộ đếm "đang xem" trên trang công khai.user_countđếm người dùng duy nhất trên kênh presence, theouser_idmà máy chủ của bạn đã ký. Hai tab, hay một điện thoại và một laptop, chỉ tính một lần. Dùng nó khi "người" mới là điều quan trọng, như giới hạn chỗ ngồi hay danh sách trực tuyến.
Bước 1: con số trong trình duyệt
Bật Gửi số người đăng ký trong cài đặt ứng dụng. Khi đó mọi người đăng ký của kênh công khai hoặc riêng tư nhận được con số hiện tại, tối đa mỗi giây một lần trong lúc nó thay đổi:
const stream = pusher.subscribe('stream-42');
stream.bind('pusher:subscription_count', ({ subscription_count }) => {
watching.textContent = subscription_count.toLocaleString();
});Không cần viết code, đoạn script nhúng một dòng làm được điều tương tự: <span data-hibira-online="stream-42">0</span> người đang xem.
Bước 2: đếm người bằng presence
Trên kênh presence, mọi người đều nhận danh sách thành viên, nên con số đã có sẵn trong trình duyệt:
const room = pusher.subscribe('presence-room-' + roomId);
const show = () => online.render(room.members.count, room.members);
room.bind('pusher:subscription_succeeded', show);
room.bind('pusher:member_added', show);
room.bind('pusher:member_removed', show);Kênh presence chứa tối đa 100 thành viên, vì mỗi thành viên nhận mọi lượt tham gia. Với toàn bộ trang web hay một sự kiện lớn, hãy cho mọi trang cùng tham gia một kênh presence lớn bằng @hibira-io/large-presence. Nó chứa tới 100.000 thành viên và gửi con số chính xác kèm một mẫu những người đang có mặt, mỗi giây một lần:
import { LargePresence } from '@hibira-io/large-presence';
const site = LargePresence.subscribe(pusher, 'presence-large-site', { maxMembers: 12 });
site.on('ready', ({ count }) => badge.render(count, site.members));
site.on('change', ({ count }) => badge.render(count, site.members));Bước 3: hỏi từ máy chủ của bạn
Máy chủ của bạn có thể đọc cùng những con số đó qua HTTP API, bằng bất kỳ thư viện máy chủ tương thích Pusher nào. Một kênh:
const res = await pusher.get({
path: '/channels/presence-room-42',
params: { info: 'user_count,subscription_count' },
});
const { occupied, user_count, subscription_count } = await res.json();Tất cả các phòng cùng lúc, phòng đông nhất lên đầu:
const res = await pusher.get({
path: '/channels',
params: { filter_by_prefix: 'presence-room-', info: 'user_count' },
});
const { channels } = await res.json();
// { "presence-room-7": { "user_count": 42 }, "presence-room-9": { "user_count": 17 } }
const busiest = Object.entries(channels)
.map(([name, { user_count }]) => ({ name, users: user_count }))
.sort((a, b) => b.users - a.users);Để kiểm tra giới hạn chỗ ngồi trước khi ký một lượt đăng ký, hãy đọc số người của phòng trong route ủy quyền kênh và từ chối khi phòng đã đầy:
app.post('/pusher/auth', requireLogin, async (req, res) => {
const { socket_id, channel_name } = req.body;
const room = await pusher.get({ path: `/channels/${channel_name}`, params: { info: 'user_count' } });
const { user_count } = await room.json();
if (user_count >= 8) return res.status(403).json({ error: 'room_full' });
res.json(pusher.authorizeChannel(socket_id, channel_name, { user_id: req.user.id, user_info: { name: req.user.name } }));
});Và khi phát hành, bạn có thể hỏi lúc đó có bao nhiêu kết nối đang đăng ký, cho biết sự kiện đã đến được bao nhiêu người:
const sent = await pusher.trigger('stream-42', 'goal', { minute: 81 }, { info: 'subscription_count' });
const { channels } = await sent.json();
console.log(`reached ${channels['stream-42'].subscription_count} viewers`);user_count chỉ hỏi được trên kênh presence; trên danh sách kênh, nó cần filter_by_prefix=presence-. Cộng số người của nhiều phòng sẽ tính hai lần người đang ở hai phòng cùng lúc; để có số người duy nhất trên toàn trang, hãy đọc GET /channels/presence-large-site?info=user_count.
Bước 4: lưu lịch sử bằng webhook
Để vẽ biểu đồ đỉnh buổi tối, hoặc gửi cảnh báo khi một phòng trống, hãy để Hibira báo cho máy chủ của bạn. Trong cổng quản lý, thêm webhook cho member_added và member_removed (kênh presence), subscription_count (kênh công khai và riêng tư, khi đã bật đếm), hoặc channel_occupied và channel_vacated:
app.post('/hibira/webhooks', express.text({ type: '*/*' }), async (req, res) => {
const webhook = pusher.webhook({ headers: req.headers, rawBody: req.body });
if (!webhook.isValid()) return res.sendStatus(401);
for (const e of webhook.getEvents()) {
if (e.name === 'member_added') await db.online.add(e.channel, e.user_id);
if (e.name === 'member_removed') await db.online.remove(e.channel, e.user_id);
if (e.name === 'subscription_count') await db.viewers.record(e.channel, e.subscription_count);
}
res.sendStatus(200);
});Mẹo
- Việc đọc con số không dùng hạn mức tin nhắn của bạn; chỉ sự kiện được phát hành mới tính là tin nhắn. Dù vậy, hãy lưu đệm câu trả lời của HTTP API vài giây trên máy chủ thay vì hỏi mỗi lần xem trang.
- Webhook có thể đến muộn hoặc đến hai lần. Dùng chúng cho lịch sử và cảnh báo, và đọc HTTP API khi cần con số chính xác ngay lúc này.
- Trên các trang công khai đông người, hãy hiện con số làm tròn ("1,2k trực tuyến"): nó ít nhảy hơn mà vẫn có cảm giác sống động.
- Con số tính theo từng ứng dụng. Nếu bạn có một ứng dụng staging và một ứng dụng production, mỗi ứng dụng chỉ thấy kết nối của mình.
- Các gói giới hạn số kết nối đồng thời, không phải con số người: xem bảng giá để biết đỉnh mỗi gói cho phép.