iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0
JavaScript

不要再說你不會後端!30 天 Node.js 降維打擊指南 系列 第 26 篇

Day 26:Socket.io 的進階玩法(Rooms 房間與 Namespace)

  • 分享至 

  • xImage
  •  

昨天我們成功建立了雙向通訊的高速公路,並學會了「單聊」與「世界廣播」。但實務上,我們最常遇到的是「群組聊天」或是「多款遊戲大廳」的場景。你總不能把 A 房間的聊天訊息,廣播給全伺服器的所有人看吧?

今天,我們就要解鎖 Socket.io 內建的兩大進階分流神器:Rooms (房間) 與 Namespaces (命名空間)。


1. Rooms (房間):動態的群組廣播

Rooms 是 Socket.io 提供的一種「伺服器端專屬」的虛擬群組機制。前端完全不知道房間的存在,一切的分組邏輯都由後端控制。一個 Socket 可以同時加入多個房間,也可以隨時退出。

核心語法:

  • socket.join('room_name'):將該客戶端加入指定房間。
  • socket.leave('room_name'):將該客戶端移出指定房間。
  • io.to('room_name').emit(...):對該房間內的所有人(包含自己)廣播。
  • socket.to('room_name').emit(...):對該房間內的所有人廣播,但不包含自己。

實作範例:專屬聊天室

io.on('connection', (socket) => {
    // 監聽前端發出的加入房間請求
    socket.on('join_room', (roomName) => {
        socket.join(roomName);
        console.log(`Socket ${socket.id} 加入了房間:${roomName}`);
        
        // 歡迎該名使用者 (只發給剛進來的這位)
        socket.emit('system_msg', `成功加入 ${roomName} 房間!`);
        
        // 通知房間裡的其他所有人
        socket.to(roomName).emit('system_msg', `有新成員加入 ${roomName} 囉!`);
    });

    // 監聽前端在房間內發送訊息
    socket.on('room_message', (data) => {
        const { room, message } = data;
        // 將訊息精準廣播給該房間的所有人
        io.to(room).emit('receive_message', {
            sender: socket.id,
            text: message
        });
    });
});

2. Namespaces (命名空間):物理級別的通道隔離

如果說 Rooms 是同一棟大樓裡的不同「會議室」,那 Namespaces 就是完全不同的「兩棟大樓」。
當你的專案非常龐大,例如有一個給一般使用者的端點 /chat,和一個給管理員專用的監控端點 /admin,我們就會使用 Namespace 來徹底隔離兩邊的邏輯與事件名稱。

核心語法:

  • 預設的 Namespace 是 /(也就是我們前面一直在用的 io.on)。
  • 自訂 Namespace 使用 io.of('/your-namespace')。

實作範例:管理員專屬通道

// 建立一個給一般使用者的 Namespace
const chatNsp = io.of('/chat');
chatNsp.on('connection', (socket) => {
    console.log('一般使用者連線到 /chat');
    // 這裡的廣播只會發給 /chat 底下的人
    chatNsp.emit('welcome', '歡迎來到一般聊天區'); 
});

// 建立一個給管理員的 Namespace
const adminNsp = io.of('/admin');

// 你可以針對特定 Namespace 加入專屬的中介軟體 (例如驗證管理員 Token)
adminNsp.use((socket, next) => {
    const token = socket.handshake.auth.token;
    if (token === 'super-secret-admin-token') {
        next();
    } else {
        next(new Error('驗證失敗,你不是管理員!'));
    }
});

adminNsp.on('connection', (socket) => {
    console.log('管理員連線到 /admin');
    adminNsp.emit('alert', '系統警告:伺服器負載過高!');
});

3. 該用哪一個?

  • 使用 Rooms 的時機:資料隔離是動態的。例如:玩家配對建立的遊戲對戰房、使用者自己創立的聊天群組。
  • 使用 Namespaces 的時機:邏輯隔離是固定的。例如:拆分「即時聊天微服務」與「後台系統監控微服務」,兩邊的權限驗證與處理邏輯完全不同。

靈活運用這兩個機制,你就能在 Node.js 中打造出足以支撐萬人同時在線,且頻道互不干擾的即時通訊巨獸!


上一篇
Day 25:突破 HTTP 的限制,WebSocket 與 Socket.io 雙向通訊
下一篇
Day 27:突破效能瓶頸(Redis 快取與微服務架構入門)
系列文
不要再說你不會後端!30 天 Node.js 降維打擊指南 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言