+5

Server-Sent Events (SSE) là gì? Chúng ta nên sử dụng nó như thế nào ?

Mở đầu

Khi nói đến việc truyền dữ liệu theo thời gian thực từ server đến client, WebSockets luôn được coi là lựa chọn hàng đầu. Tuy nhiên, WebSockets không phải lúc nào cũng là giải pháp lý tưởng. SSE (Server-Sent Events) đơn giản hơn WebSockets chủ yếu vì nó tận dụng giao thức HTTP sẵn có, trong khi WebSockets là một giao thức riêng biệt, phức tạp hơn về cả thiết kế lẫn triển khai.

SSE là gì?

Server-Sent Events (SSE) là một công nghệ truyền dữ liệu thời gian thực từ server xuống client, được tiêu chuẩn hóa trong HTML5. SSE hoạt động theo cơ chế một chiều, tức là chỉ cho phép server gửi dữ liệu xuống client thông qua một kết nối HTTP duy nhất. Khi client (thường là trình duyệt) mở một kết nối SSE tới server, server sẽ giữ kết nối đó luôn mở và liên tục gửi các cập nhật mới xuống. Điều này đặc biệt phù hợp cho các ứng dụng cần cập nhật thông tin theo thời gian thực, ví dụ như bảng điều khiển dữ liệu trực tiếp (dashboard), thông báo hệ thống (notifications), hoặc luồng tin tức mới nhất (news feed).

Ưu điểm nổi bật của SSE là đơn giản và dễ triển khai, vì nó chỉ sử dụng** HTTP tiêu chuẩn** chứ không cần giao thức phức tạp riêng như WebSockets. Bên cạnh đó, trình duyệt hiện đại hỗ trợ sẵn với đối tượng EventSource, giúp lập trình viên chỉ cần vài dòng code để nhận dữ liệu từ server. Tính năng tự động reconnect cũng giúp SSE ổn định hơn trong môi trường mạng kém.

Tuy nhiên, do chỉ hỗ trợ một chiều từ server xuống client, SSE không phù hợp với các ứng dụng cần giao tiếp hai chiều như chat hay game. Dù vậy, với các nhu cầu truyền dữ liệu một chiều đơn giản và hiệu quả, SSE vẫn là một lựa chọn tối ưu.

Ưu điểm của SSE

Độ trễ thấp cho cập nhật thời gian thực

Với các ứng dụng cần cập nhật dữ liệu liên tục theo thời gian thực, như hệ thống thông báo, bảng giá chứng khoán hoặc bảng điều khiển dữ liệu (dashboard), SSE là giải pháp lý tưởng. Thay vì client phải chủ động gửi request định kỳ để kiểm tra xem có dữ liệu mới không (cách gọi là polling), SSE cho phép server chủ động đẩy dữ liệu xuống ngay lập tức khi có cập nhật mới. Điều này giúp giảm tối đa độ trễ (latency), đồng thời mang lại trải nghiệm mượt mà hơn cho người dùng cuối.

Tối ưu tài nguyên

Với các hệ thống sử dụng polling (client liên tục hỏi server "có dữ liệu mới chưa?"), server phải xử lý rất nhiều request vô nghĩa — kể cả khi không có gì mới để trả về. Điều này gây lãng phí tài nguyên cả ở server lẫn network. SSE giải quyết vấn đề này bằng cách giữ một kết nối duy nhất và chỉ gửi dữ liệu khi thực sự có thông tin mới. Điều này không chỉ giúp giảm tải hệ thống, mà còn tiết kiệm băng thông đáng kể.

Đơn giản hơn WebSockets

WebSockets rất mạnh mẽ nhờ khả năng giao tiếp hai chiều, nhưng đi kèm với đó là độ phức tạp cao. WebSockets cần một quá trình handshake đặc biệt, yêu cầu quản lý kết nối, heartbeat, reconnect thủ công, và hoạt động trên giao thức TCP riêng biệt sau handshake. Trong khi đó, SSE chỉ là một kết nối HTTP/1.1 đơn thuần, dễ triển khai hơn rất nhiều, đặc biệt trong môi trường web và microservices. Tính đơn giản của SSE giúp lập trình viên viết ít code hơn, giảm sai sót và rút ngắn thời gian phát triển.

Tự động kết nối lại (Built-in Reconnection)

Mất kết nối do lỗi mạng là điều khó tránh, nhưng với SSE, bạn không phải tự lo xử lý reconnect. Đối tượng EventSource trên trình duyệt sẽ tự động thử kết nối lại khi gặp sự cố. Điều này giúp ứng dụng bền bỉ hơn trước những tình huống gián đoạn mạng mà không cần thêm bất kỳ logic đặc biệt nào từ phía lập trình viên. Đây là lợi thế rất lớn so với WebSockets, nơi bạn phải tự viết cơ chế reconnect bằng tay.

Ví dụ đơn giản

Backend (Go)

package main

import (
    "fmt"
    "net/http"
    "time"
)

func sseHandler(w http.ResponseWriter, r *http.Request) {
    // Set headers for SSE
    w.Header().Set("Content-Type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection", "keep-alive")

    flusher, ok := w.(http.Flusher)
    if !ok {
        http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
        return
    }

    // Sending events every second
    for i := 0; i < 10; i++ {
        fmt.Fprintf(w, "event:welcome\ndata: Message %d\n\n", i)

        flusher.Flush()

        time.Sleep(time.Second)
    }
}

func main() {
    http.HandleFunc("/events", sseHandler)
    fmt.Println("Server listening on :8080")
    http.ListenAndServe(":8080", nil)
}
  • w.Header().Set("Content-Type", "text/event-stream"): Đảm bảo rằng client hiểu đây là một kết nối SSE.
  • w.Header().Set("Cache-Control", "no-cache"): Ngăn trình duyệt và các bộ đệm trung gian (proxy) lưu trữ dữ liệu SSE.
  • w.Header().Set("Connection", "keep-alive"): Giữ kết nối luôn mở để server có thể liên tục gửi dữ liệu xuống client.

Frontend (JavaScript)


const eventSource = new EventSource('http://localhost:8080/events');


eventSource.onmessage = (event) => {
    console.log('Received message:', event.data);
    document.getElementById('messages').innerHTML += `<p>${event.data}</p>`;
};


eventSource.addEventListener('welcome', (event) => {
    console.log(event.data);
});


eventSource.onopen = () => {
    console.log('Connection opened!');
};


eventSource.onerror = (error) => {
    console.log('Error occurred:', error);
};


function closeConnection() {
    eventSource.close();
}

So sánh giữa SSE và WebSockets

Tính năng SSE WebSockets
Giao thức HTTP/1.1 TCP (riêng biệt)
Hai chiều ✔️
Đơn giản ✔️
Hỗ trợ proxy ✔️
Tự động reconnect ✔️ ❌ (phải tự làm)

Khi nào nên dùng SSE

Những trường hợp này đều là luồng dữ liệu một chiều từ server xuống client, cần độ trễ thấp, dễ triển khai, không cần giao tiếp hai chiều → đúng bài của SSE.

  • Thông báo trực tiếp
  • Bảng điều khiển thời gian thực
  • Cập nhật thị trường chứng khoán
  • Bảng tin mạng xã hội
  • Tỉ số thể thao trực tiếp
  • Giám sát hệ thống

Kết luận

SSE là một công cụ mạnh mẽ nhưng cực kỳ đơn giản dành cho việc cập nhật dữ liệu thời gian thực. Công nghệ này đặc biệt phù hợp khi bạn chỉ cần truyền dữ liệu một chiều từ server xuống client mà không phải gánh thêm sự phức tạp của WebSockets. Các tính năng tích hợp sẵn như tự động kết nối lại cùng với việc dựa trên giao thức HTTP tiêu chuẩn giúp SSE trở thành lựa chọn tuyệt vời cho nhiều ứng dụng real-time hiện nay.

Tuy nhiên, khi triển khai trong môi trường production, chúng ta cần cân nhắc kỹ lưỡng về các giới hạn của SSE, đặc biệt là khả năng mở rộng (scalability) khi có quá nhiều kết nối đồng thời, cũng như việc SSE chỉ hỗ trợ kết nối đơn hướng. Nếu bài toán yêu cầu giao tiếp hai chiều hoặc hiệu năng cao cho hàng trăm nghìn kết nối cùng lúc, có thể WebSockets hoặc các giải pháp chuyên dụng khác sẽ phù hợp hơn.

Tài liệu tham khảo


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí