WebSocket và thời gian thực: xây chat, thông báo mà không cần tải lại trang

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

Chat, thông báo tức thì, bảng điểm trực tiếp, cộng tác trên cùng tài liệu... đều cần dữ liệu đến người dùng ngay khi có thay đổi, thay vì họ phải tải lại trang. WebSocket là công nghệ chuẩn cho kiểu giao tiếp hai chiều này. Bài viết giúp bạn hiểu nó khác HTTP thế nào và khi nào dùng.

Vấn đề của HTTP thông thường

HTTP theo mô hình yêu cầu-phản hồi: client hỏi, server mới trả lời. Server không thể tự đẩy dữ liệu xuống. Để mô phỏng thời gian thực, người ta từng dùng polling: client hỏi lặp đi lặp lại mỗi vài giây. Cách này lãng phí (đa số lần hỏi không có gì mới) và có độ trễ.

WebSocket giải quyết thế nào?

WebSocket thiết lập một kết nối duy nhất, lâu dài và hai chiều giữa client và server. Nó bắt đầu bằng một yêu cầu HTTP "nâng cấp" (upgrade), sau đó giữ kết nối mở để hai bên gửi thông điệp cho nhau bất cứ lúc nào, với chi phí mỗi thông điệp rất nhỏ.

Ví dụ tối giản

// Server Node.js với thư viện wsconst { WebSocketServer } = require('ws');const wss = new WebSocketServer({ port: 8080 });wss.on('connection', (socket) => {  socket.on('message', (data) => {    // phát lại cho mọi client đang kết nối    for (const client of wss.clients) {      if (client.readyState === 1) client.send(data.toString());    }  });});
// Client trong trình duyệtconst ws = new WebSocket('wss://example.com/chat');ws.onopen = () => ws.send('Xin chào mọi người');ws.onmessage = (e) => console.log('Nhận:', e.data);ws.onclose = () => console.log('Mất kết nối');

Dùng wss:// (WebSocket bảo mật qua TLS) trong môi trường thật, tương tự HTTPS.

Các lựa chọn khác

  • Server-Sent Events (SSE): server đẩy luồng sự kiện một chiều tới client qua HTTP thông thường. Đơn giản, tự kết nối lại, rất hợp với thông báo và cập nhật tiến độ khi client không cần gửi nhiều lên.
  • Long polling: client giữ yêu cầu mở cho tới khi có dữ liệu, dự phòng khi không dùng được WebSocket.
  • Socket.IO: thư viện bao WebSocket, bổ sung tự kết nối lại, phòng (room), xác nhận thông điệp và dự phòng khi cần.
  • Dịch vụ quản lý: một số dịch vụ cloud lo hạ tầng thời gian thực, đỡ phải tự vận hành.

Nếu chỉ cần server đẩy thông báo, SSE thường đủ và đơn giản hơn WebSocket.

Những thách thức khi chạy thật

  • Xác thực: kiểm tra người dùng khi kết nối (token trong tham số hoặc thông điệp đầu tiên) và phân quyền cho từng kênh; đừng để ai cũng nghe được mọi phòng.
  • Mở rộng nhiều server: client A nối vào server 1, client B nối vào server 2; để A nhắn cho B bạn cần một kênh chung như Redis Pub/Sub hoặc hàng đợi thông điệp để các server chuyển tiếp cho nhau.
  • Kết nối bị rớt: mạng di động hay chập chờn; client cần tự kết nối lại có backoff và khôi phục trạng thái đã bỏ lỡ.
  • Heartbeat (ping/pong): phát hiện kết nối chết và dọn dẹp.
  • Giới hạn tài nguyên: mỗi kết nối chiếm bộ nhớ và mô tả tệp; đặt giới hạn kích thước thông điệp và tần suất gửi để chống lạm dụng.
  • Proxy và cân bằng tải: cần cấu hình hỗ trợ nâng cấp kết nối và thời gian chờ đủ dài.

Mẫu thiết kế gợi ý

Hãy xem WebSocket là kênh phân phối, còn nguồn sự thật vẫn là API và database. Khi người dùng gửi tin nhắn, lưu vào database qua luồng bình thường rồi phát sự kiện cho những người liên quan. Nhờ vậy nếu kết nối rớt, client chỉ việc gọi API lấy lại những gì đã lỡ. Cách thiết kế này bền hơn nhiều so với việc coi kết nối là nơi lưu trạng thái.

Bài tập gợi ý

Hãy xây một phòng chat nhỏ: server Node.js dùng thư viện ws, giao diện HTML thuần có ô nhập và danh sách tin nhắn. Sau đó thêm tên người dùng, lưu lịch sử vào database và gửi lại 20 tin gần nhất khi một người mới vào phòng. Tiếp theo thử tắt server giữa chừng và xem giao diện tự kết nối lại. Hãy luôn kiểm tra lại bằng thực hành thay vì chỉ đọc lý thuyết: dựng một dự án nhỏ, cố tình tạo lỗi, quan sát log và công cụ gỡ lỗi, rồi sửa.

Khi đã chạy tốt trên một server, hãy thử chạy hai bản và nối chúng bằng Redis Pub/Sub để thấy tin nhắn đi xuyên các tiến trình, đây là bước quan trọng nhất để chuyển từ bản thử sang hệ thống thật.

Kết luận

WebSocket mở ra trải nghiệm thời gian thực, nhưng đi kèm bài toán về xác thực, mở rộng và độ bền kết nối. Hãy bắt đầu bằng một ví dụ phòng chat nhỏ, sau đó thử mở hai tab trình duyệt để thấy tin nhắn xuất hiện tức thì. Khi cần thật sự, cân nhắc giữa WebSocket, SSE hoặc dịch vụ quản lý tùy yêu cầu.

Muốn học bài bản và có lộ trình rõ ràng? Bạn có thể xem các khóa học trên codebem.com.

author_photo
Nguyễn Đình Cường

0 comment