SSE — nó là gì, Server-Sent Events và phát trực tiếp một chiều

Tác giả: IT Sectr Đã đăng: 2026-06-02 Thời gian đọc: 8 phút

SSE (Server-Sent Events) là một tiêu chuẩn W3C cho phép máy chủ gửi dữ liệu trực tiếp đến máy khách qua một kết nối HTTP duy nhất ở chế độ một chiều. Không giống WebSocket, SSE hoạt động trên HTTP thông thường và không yêu cầu giao thức đặc biệt hoặc thư viện ở phía máy khách. Theo thông số kỹ thuật W3C HTML Living Standard (2025), EventSource API được hỗ trợ trong tất cả các trình duyệt hiện đại, bao gồm Chrome, Firefox, Safari và Edge.

Những điểm chính

  • SSE là tiêu chuẩn truyền dữ liệu một chiều từ máy chủ đến máy khách qua kết nối HTTP.
  • EventSource API là giao diện trình duyệt tích hợp để nhận SSE mà không cần thư viện bên ngoài.
  • Tự động kết nối lại — trình duyệt tự động khôi phục kết nối khi bị ngắt.
  • Giao thức văn bản — dữ liệu được truyền ở định dạng text/event-stream với định dạng văn bản đơn giản.
  • Giao tiếp một chiều — SSE phù hợp cho thông báo, nguồn cấp tin tức, bảng tín hiệu và giám sát, nhưng không phù hợp cho trò chuyện.

SSE là gì?

SSE (Server-Sent Events) là một công nghệ cho phép máy chủ web gửi dữ liệu đến máy khách bất cứ lúc nào sau khi thiết lập kết nối. Nó được WHATWG chuẩn hóa như một phần của HTML Living Standard và sử dụng kiểu MIME text/event-stream. SSE hỗ trợ truyền dữ liệu văn bản với khả năng chỉ định mã nhận dạng tin nhắn, loại sự kiện và độ trễ kết nối lại.

Không giống WebSocket, yêu cầu giao thức hai chiều và yêu cầu nâng cấp, SSE hoạt động trên HTTP thông thường. Máy chủ đặt tiêu đề Content-Type: text/event-stream, gửi dữ liệu theo từng đoạn và giữ kết nối mở. Máy khách nhận dữ liệu qua EventSource API của trình duyệt, tự động phân tích luồng và tạo sự kiện.

Theo CanIUse (2025), EventSource API được hỗ trợ trong 97,5% trình duyệt trên toàn cầu. Nó không được hỗ trợ trong Internet Explorer và một số trình duyệt di động (Samsung Internet trước phiên bản 7.0). Đối với những trường hợp này, có các polyfill mô phỏng EventSource qua XHR streaming. SSE không hoạt động với HTTP/1.1 pipelining, nhưng tương thích hoàn toàn với HTTP/2 server push.

Lịch sử và tiêu chuẩn hóa

SSE được đề xuất như một phần của thông số kỹ thuật HTML5 vào năm 2009 dưới tên Server-Sent DOM Events. Việc triển khai đầu tiên xuất hiện trong Opera 9.0, sau đó là Firefox 6.0 (2011), Chrome 9.0 (2011) và Safari 5.0 (2010). Năm 2015, thông số kỹ thuật đã được chuyển sang một phần riêng của HTML Living Standard. Bất chấp lịch sử hơn một thập kỷ, SSE vẫn ít phổ biến hơn WebSocket do bản chất một chiều của nó.

Cách SSE hoạt động

Cơ chế hoạt động của SSE như sau: máy khách tạo một thể hiện EventSource với URL của điểm cuối máy chủ. Trình duyệt gửi yêu cầu GET với tiêu đề Accept: text/event-stream. Máy chủ phản hồi với trạng thái 200 OK và tiêu đề Content-Type: text/event-stream, sau đó bắt đầu gửi dữ liệu ở định dạng event-stream. Kết nối vẫn mở cho đến khi máy chủ gửi tín hiệu kết thúc hoặc máy khách gọi close().

phía máy chủ, dữ liệu được gửi theo từng đoạn (chunked transfer encoding). Mỗi đoạn dữ liệu là một tin nhắn văn bản bao gồm các dòng trường (event, data, id, retry). Máy chủ có thể gửi tin nhắn bất cứ lúc nào, làm cho SSE trở nên lý tưởng cho thông báo và cập nhật trạng thái. Kết nối không yêu cầu trao đổi gói tin heartbeat liên tục (như WebSocket), mặc dù trường retry kiểm soát tần suất kết nối lại.

Theo kiểm tra hiệu suất (2024), SSE cung cấp thông lượng lên đến 10.000 tin nhắn mỗi giây cho mỗi kết nối với kích thước tin nhắn 256 byte. Ở phía máy chủ, mỗi kết nối SSE tiêu thụ khoảng 5–10 KB bộ nhớ, cho phép một máy chủ hỗ trợ hơn 50.000 kết nối đồng thời với 1 GB RAM. Con số này thấp hơn đáng kể so với WebSocket do không có giao thức nhị phân.

Định dạng event-stream

Định dạng text/event-stream là một giao thức văn bản đơn giản, trong đó mỗi tin nhắn bao gồm các trường có tên được phân tách bằng ký tự xuống dòng. Mỗi trường có định dạng “Tên trường: giá trị”. Các tin nhắn được phân tách bằng hai ký tự xuống dòng (\n\n).

Các trường được hỗ trợ: event (loại sự kiện, mặc định là message), data (chuỗi dữ liệu, có thể nhiều dòng), id (mã nhận dạng sự kiện cuối cùng, được lưu trong Last-Event-ID), retry (thời gian kết nối lại tính bằng mili giây). Nhận xét bắt đầu bằng dấu hai chấm (:) và bị trình phân tích bỏ qua, nhưng có thể được sử dụng cho heartbeat.

TrườngBắt buộcMục đích
eventKhôngLoại sự kiện (mặc định là message)
dataChuỗi dữ liệu tin nhắn
idKhôngMã nhận dạng sự kiện cho Last-Event-ID
retryKhôngĐộ trễ kết nối lại tính bằng ms

Ví dụ về event-stream

text
: heartbeat comment
event: update
data: {"user": "Alice", "action": "typing"}
id: 1001

event: notification
data: {"type": "info", "text": "New version available"}
data: {"type": "action", "url": "/upgrade"}
retry: 3000

event: close
data: Session ended

API EventSource ở phía máy khách

EventSource API là giao diện trình duyệt tích hợp để nhận SSE. Để tạo kết nối, chỉ cần gọi hàm tạo với URL của điểm cuối. EventSource tự động thiết lập kết nối, xử lý kết nối lại và phân tích các tin nhắn đến thành các sự kiện JavaScript.

Các sự kiện EventSource: open (kết nối đã được thiết lập), message (đã nhận được tin nhắn mà không có sự kiện được chỉ định), error (lỗi kết nối). Đối với các sự kiện tùy chỉnh (event: custom), bạn có thể sử dụng addEventListener với tên sự kiện. EventSource tự động gửi tiêu đề Last-Event-ID khi kết nối lại, cho phép máy chủ tiếp tục luồng từ nơi bị gián đoạn.

Theo tài liệu MDN (2025), EventSource hỗ trợ CORS và truyền thông tin xác thực (withCredentials). EventSource không phù hợp để gửi tiêu đề tùy chỉnh hoặc phần thân yêu cầu — cần triển khai thủ công qua fetch + ReadableStream. EventSource không hỗ trợ dữ liệu nhị phân — chỉ văn bản và JSON.

Mã JavaScript phía máy khách

js
const eventSource = new EventSource('/api/events/stream');

eventSource.addEventListener('open', () => {
    console.log('Đã mở kết nối SSE');
});

eventSource.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    console.log('Đã nhận:', data);
    renderUpdate(data);
});

eventSource.addEventListener('notification', (event) => {
    const notification = JSON.parse(event.data);
    showNotification(notification.text);
});

eventSource.addEventListener('error', (error) => {
    console.error('Lỗi SSE:', error);
    // Trình duyệt tự động kết nối lại
});

// Đóng kết nối
eventSource.close();

SSE so với WebSocket: so sánh

SSE và WebSocket là hai công nghệ khác nhau cho giao tiếp thời gian thực, mỗi công nghệ có thế mạnh riêng. WebSocket phù hợp cho trao đổi dữ liệu hai chiều (trò chuyện, trò chơi, chỉnh sửa cộng tác), trong khi SSE dành cho luồng một chiều từ máy chủ đến máy khách (thông báo, nguồn cấp tin tức, bảng tín hiệu).

Sự khác biệt chính là WebSocket yêu cầu yêu cầu nâng cấp từ HTTP/1.1 lên giao thức WebSocket (ws://), có thể bị chặn bởi proxy doanh nghiệp. SSE hoạt động trên HTTP thông thường, đi qua bất kỳ proxy nào và không yêu cầu cấu hình đặc biệt cho máy chủ. SSE cũng dễ triển khai hơn — máy chủ không cần thư viện bổ sung, chỉ cần định dạng phản hồi HTTP một cách chính xác.

Theo kiểm tra so sánh (2024), trên một tiến trình máy chủ, SSE hỗ trợ nhiều hơn 30–50% kết nối so với WebSocket do giao thức đơn giản hơn. Tuy nhiên, SSE có độ trễ cao hơn (50–200 ms so với 10–50 ms của WebSocket) vì SSE sử dụng HTTP phân đoạn thay vì luồng hai chiều hoàn chỉnh với khung nhị phân.

Đặc điểmSSEWebSocket
HướngMáy chủ → máy kháchHai chiều
Giao thứcHTTP (text/event-stream)ws:// / wss:// (RFC 6455)
Trình duyệt97,5% (EventSource tích hợp)97% (WebSocket tích hợp)
Dữ liệuChỉ văn bản / JSONVăn bản + nhị phân (Blob, ArrayBuffer)
Xử lý proxyĐi qua bất kỳ proxy nàoYêu cầu cấu hình proxy
Kết nối lạiTự động (trình duyệt)Triển khai thủ công
Lịch sửLast-Event-IDKhông có lịch sử tích hợp

Cách triển khai SSE trên máy chủ

Triển khai SSE trên máy chủ không yêu cầu thư viện — chỉ cần đặt các tiêu đề HTTP chính xác và gửi dữ liệu ở định dạng text/event-stream. Hãy xem ví dụ trong Node.js sử dụng mô-đun http tích hợp. Máy chủ đặt các tiêu đề Content-Type và Cache-Control, sau đó gửi tin nhắn mỗi N giây.

Theo MDN Web Docs (2025), các tiêu đề bắt buộc cho SSE là: Content-Type: text/event-stream, Cache-Control: no-cache và Connection: keep-alive. Nếu không có Cache-Control, trình duyệt có thể lưu vùng đệm SSE stream, làm ngừng việc phân phối. Connection: keep-alive hướng dẫn trình duyệt giữ kết nối mở.

Mã máy chủ trong Node.js

js
const http = require('http');

http.createServer((req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });

    let eventId = 0;
    const interval = setInterval(() => {
        eventId++;
        res.write(`id: ${eventId}\n`);
        res.write(`event: update\n`);
        res.write(`data: {"time": "${new Date().toISOString()}", "id":${eventId}}\n\n`);
    }, 2000);

    req.on('close', () => {
        clearInterval(interval);
    });
}).listen(3000);

SSE trong Python (Flask)

python
from flask import Response, Flask
import time
import json

app = Flask(__name__)

@app.route('/stream')
def stream():
    def generate():
        event_id = 0
        while True:
            event_id += 1
            data = json.dumps(
                {'ticker': 'AAPL', 'price': 150.25})
            yield f'id: {event_id}\nevent: price\ndata: {data}\n\n'
            time.sleep(1)
    return Response(generate(),
        mimetype='text/event-stream')

SSE trong ứng dụng di động

Sử dụng SSE trong ứng dụng di động bị hạn chế do thiếu triển khai EventSource gốc cho iOS và Android. Trên các nền tảng di động, SSE được triển khai thông qua các thư viện bên thứ ba: trên iOS — qua URLSession với NSURLProtocol, trên Android — qua OkHttp với hỗ trợ SSE (okhttp-sse). Đối với React Native và Flutter, có các gói mô phỏng EventSource.

Trên iOS, triển khai SSE gốc có thể thực hiện qua URLSessionDataDelegate. Khi nhận dữ liệu trong phương thức urlSession(_:dataTask:didReceive:), ứng dụng tích lũy bộ đệm và phân tích định dạng event-stream thủ công. Theo blog phát triển iOS (2024), mức tiêu thụ pin với SSE trên iOS thấp hơn 40% so với kết nối WebSocket liên tục do không có gói tin heartbeat.

Trên Android, OkHttp cung cấp lớp EventSource.Factory để đăng ký các luồng SSE. Ứng dụng Android có thể sử dụng SSE cho thông báo khi FCM không khả dụng hoặc để đồng bộ dữ liệu trong nền. SSE trên Android hoạt động tốt với WorkManager cho các tác vụ nền kéo dài. Theo tài liệu OkHttp (2025), okhttp-sse hỗ trợ tự động kết nối lại với trình lắng nghe tùy chỉnh.

Câu hỏi thường gặp

SSE khác WebSocket như thế nào?

SSE là truyền một chiều (máy chủ → máy khách) qua HTTP, không cần thư viện trên máy khách. WebSocket là truyền hai chiều với giao thức nhị phân. SSE dễ triển khai hơn, WebSocket phù hợp cho các tác vụ mà máy khách cũng gửi dữ liệu.

SSE có hỗ trợ dữ liệu nhị phân không?

Không, SSE chỉ truyền dữ liệu văn bản. Đối với dữ liệu nhị phân (hình ảnh, âm thanh), cần mã hóa Base64, làm tăng kích thước lên 33%. Đối với luồng nhị phân, tốt hơn nên sử dụng WebSocket.

SSE xử lý ngắt kết nối như thế nào?

EventSource tự động kết nối lại khi xảy ra ngắt kết nối. Thời gian trễ được đặt bởi trường retry trong luồng (mặc định 1000 ms). Khi kết nối lại, trình duyệt gửi tiêu đề Last-Event-ID, cho phép máy chủ tiếp tục luồng từ nơi bị gián đoạn.

Một trình duyệt có thể giữ bao nhiêu kết nối SSE?

Mỗi trình duyệt có giới hạn về số lượng kết nối HTTP đồng thời đến một miền. Đối với HTTP/1.1 — 6–8 kết nối cho mỗi miền, đối với HTTP/2 — lên đến 100. SSE sử dụng một kết nối, do đó không có cạnh tranh với các yêu cầu khác.

Có thể sử dụng SSE cho trò chuyện không?

SSE chỉ phù hợp để nhận tin nhắn (đến). Để gửi tin nhắn (đi), cần một yêu cầu HTTP riêng (POST). Đối với trò chuyện đầy đủ, thuận tiện hơn khi sử dụng WebSocket hoặc Socket.IO với giao tiếp hai chiều trong một kết nối duy nhất.

Tổng kết

  • SSE là tiêu chuẩn truyền dữ liệu một chiều từ máy chủ đến máy khách qua kết nối HTTP thông thường mà không cần thư viện bổ sung.
  • EventSource API là giao diện trình duyệt tích hợp được 97,5% trình duyệt hiện đại hỗ trợ.
  • Giao thức văn bản đơn giản text/event-stream với các trường event, data, id và retry.
  • Tự động kết nối lại với hỗ trợ Last-Event-ID để tiếp tục luồng từ nơi bị gián đoạn.
  • Hiệu quả — SSE hỗ trợ nhiều kết nối máy chủ hơn (50.000+) so với WebSocket nhờ giao thức đơn giản hơn.
  • Trên nền tảng di động SSE được triển khai qua OkHttp (Android) hoặc URLSession (iOS) với phân tích luồng thủ công.
  • Đối với luồng một chiều (thông báo, nguồn cấp, bảng tín hiệu) hãy chọn SSE, cho giao tiếp hai chiều — WebSocket hoặc Socket.IO.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm