Giới thiệu
Nếu bạn từng muốn máy chủ của mình đẩy cập nhật trực tiếp đến trình duyệt mà không cần client liên tục kiểm tra, Server-Sent Events (SSE) là một giải pháp đơn giản và hiệu quả. Bài viết này sẽ khám phá SSE là gì, cách triển khai nó trong Golang, và lý do tại sao phía client cần sử dụng EventSource.
SSE là gì?
SSE là một tiêu chuẩn cho phép máy chủ gửi cập nhật liên tục qua một kết nối HTTP duy nhất đến client. Khác với WebSockets, SSE là một chiều — máy chủ gửi dữ liệu, nhưng client không thể gửi tin nhắn trở lại trên cùng một kết nối.
Ứng dụng phổ biến:
- Bảng điều khiển trực tiếp và hệ thống giám sát.
- Thông báo trò chuyện hoặc cập nhật nguồn tin xã hội.
- Nhật ký thời gian thực hoặc bảng giá cổ phiếu.
Tạo máy chủ SSE trong Go
Dưới đây là cách triển khai một máy chủ SSE cơ bản bằng Go:
go
package main
import (
"fmt"
"net/http"
"time"
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
server := http.Server{
Addr: ":8080",
Handler: router,
}
router.HandleFunc("/sse", handleEvents).Methods("GET")
fmt.Println("Máy chủ SSE đang chạy trên :8080")
err := server.ListenAndServe()
if err != nil {
panic(err)
}
}
func handleEvents(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
fmt.Fprintf(w, "data: %s\n\n", time.Now().String())
if f, ok := w.(http.Flusher); ok { f.Flush() }
case <-r.Context().Done():
return
}
}
}
Điểm chính:
Content-Type: text/event-streamlà bắt buộc.- Mỗi tin nhắn phải bắt đầu bằng
data:và kết thúc bằng hai dòng mới \n\n. - Sử dụng
http.Flusherđể đẩy dữ liệu ngay lập tức mà không cần đệm.
Phía Client – EventSource
SSE được thiết kế cho trình duyệt, với API EventSource có sẵn. Điều này làm cho việc nhận sự kiện từ máy chủ trở nên rất đơn giản:
html
<script>
const es = new EventSource("http://localhost:8080/sse");
es.onopen = () => console.log("Kết nối SSE thành công");
es.onmessage = e => console.log("tin nhắn:", e.data);
es.onerror = e => console.error("Lỗi SSE", e);
</script>
Một số điểm nổi bật:
- EventSource tự động kết nối lại nếu kết nối bị mất.
- Nó phân tích dữ liệu: tin nhắn được gửi từ máy chủ.
- Đây là lý do client thường cần một trình duyệt hoặc môi trường JS hỗ trợ EventSource.
SSE so với WebSockets
Trong khi SSE là hoàn hảo cho việc truyền dữ liệu từ máy chủ → client, cho giao tiếp hai chiều, nơi client cũng gửi tin nhắn đến máy chủ trong thời gian thực, WebSockets phù hợp hơn.
| Đặc điểm | SSE | WebSockets |
|---|---|---|
| Hướng | Một chiều (server → client) | Hai chiều |
| Giao thức | Hoạt động qua HTTP/HTTPS | Phức tạp hơn nhưng linh hoạt |
| Triển khai | Đơn giản | Phức tạp hơn |
Lưu ý nhanh về Streaming HTTP
SSE là một loại streaming HTTP, nơi máy chủ gửi dữ liệu theo từng khối mà không đóng kết nối. Streaming HTTP không chỉ giới hạn ở trình duyệt và có thể được sử dụng trong giao tiếp giữa các máy chủ.
Xem video demo
Tôi đã tạo một video ngắn để trình bày cách triển khai SSE trong Go, bao gồm mã máy chủ và cách EventSource xử lý dữ liệu trong trình duyệt.
Kết luận
SSE là một cách nhẹ nhàng và hiệu quả để đẩy cập nhật trực tiếp từ máy chủ đến trình duyệt. Nó đơn giản hơn WebSockets khi bạn chỉ cần giao tiếp từ máy chủ đến client, làm cho nó trở nên lý tưởng cho bảng điều khiển, nhật ký và thông báo.
Câu hỏi thường gặp (FAQ)
SSE có thể sử dụng cho những ứng dụng nào?
SSE rất phù hợp cho các ứng dụng yêu cầu cập nhật liên tục như bảng điều khiển trực tiếp, thông báo, và nhật ký thời gian thực.
Có thể sử dụng SSE với các ngôn ngữ khác ngoài Go không?
Có, SSE là một tiêu chuẩn HTTP và có thể được triển khai trên nhiều ngôn ngữ khác nhau như Node.js, Python, Java, v.v.
SSE có thể thay thế WebSockets không?
SSE không thể thay thế WebSockets hoàn toàn, nhưng nó là một giải pháp tốt cho các tình huống mà chỉ cần giao tiếp từ máy chủ đến client.