Giới thiệu về Sự kiện gửi từ máy chủ (SSE)
Sự kiện gửi từ máy chủ (SSE) là một công nghệ đẩy từ máy chủ cho phép máy khách tự động nhận các cập nhật từ máy chủ thông qua một kết nối HTTP. Nó mô tả cách máy chủ khởi tạo việc truyền dữ liệu đến máy khách sau khi thiết lập kết nối ban đầu. Thông thường, nó được sử dụng để gửi cập nhật tin nhắn hoặc dòng dữ liệu liên tục đến máy khách trình duyệt, với mục tiêu là tăng cường luồng dữ liệu qua giao diện lập trình ứng dụng JavaScript được gọi là EventSource. Các máy khách có thể sử dụng API này để yêu cầu một URL cụ thể để nhận luồng sự kiện. Như một phần của HTML5, API EventSource đã được tiêu chuẩn hóa bởi WHATWG. Kiểu phương tiện cho SSE là văn bản / luồng-sự-kiện (text/event-stream).
Lưu ý: Sự khác biệt lớn nhất giữa SSE và Websocket là SSE là công nghệ đẩy tin nhắn từ máy chủ đến máy khách một chiều, trong khi Websocket là công nghệ đẩy tin nhắn hai chiều. Đôi khi, khi yêu cầu kinh doanh không phức tạp, việc đẩy tin nhắn một chiều của SSE là đủ. Điều này tương tự như công nghệ được sử dụng trong cuộc trò chuyện của trí tuệ nhân tạo ChatGPT.
Ví dụ SSE Fiber
package main
import (
"bufio"
"fmt"
"log"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/valyala/fasthttp"
)
// Mô phỏng máy khách HTML, đây là một ví dụ về phía trước nhận thông báo đẩy từ máy chủ trong JS, trong kịch bản kinh doanh thực tế, phía trước sẽ thực hiện điều này.
var index = []byte(`<!DOCTYPE html>
<html>
<body>
<h1>Các thông báo SSE</h1>
<div id="result"></div>
<script>
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("http://127.0.0.1:3000/sse");
source.onmessage = function(event) {
document.getElementById("result").innerHTML += event.data + "<br>";
};
} else {
document.getElementById("result").innerHTML = "Xin lỗi, trình duyệt của bạn không hỗ trợ sự kiện gửi từ máy chủ...";
}
</script>
</body>
</html>
`)
func main() {
// Thể hiện Fiber
app := fiber.New()
// Hạn chế CORS, cho phép truy cập từ bất kỳ miền nào
app.Use(cors.New(cors.Config{
AllowOrigins: "*",
AllowHeaders: "Cache-Control",
AllowCredentials: true,
}))
// Truy cập đường dẫn /, chúng ta trước tiên trả về trang phía trước, cho phép phía trước yêu cầu phía sau để bắt đầu đẩy thông báo SSE
app.Get("/", func(c *fiber.Ctx) error {
c.Response().Header.SetContentType(fiber.MIMETextHTMLCharsetUTF8)
return c.Status(fiber.StatusOK).Send(index)
})
// Địa chỉ đẩy thông báo SSE
app.Get("/sse", func(c *fiber.Ctx) error {
// Thiết lập tiêu đề HTTP SSE, chú ý đến Content-Type
c.Set("Content-Type", "text/event-stream")
c.Set("Cache-Control", "no-cache")
c.Set("Connection", "keep-alive")
c.Set("Transfer-Encoding", "chunked")
// Bắt đầu đẩy thông báo
c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) {
fmt.Println("WRITER")
var i int
// Mô phỏng việc liên tục đẩy thông báo đến máy khách
for {
i++
msg := fmt.Sprintf("%d - thời gian là %v", i, time.Now())
// Sử dụng writer và hàm Fprintf để đẩy thông báo đến máy khách, trong kịch bản kinh doanh thực tế, văn bản JSON có thể được gửi để thuận tiện cho việc xử lý phía trước
fmt.Fprintf(w, "data: Thông báo: %s\n\n", msg)
fmt.Println(msg)
// Xả dữ liệu đầu ra đến máy khách
err := w.Flush()
if err != nil {
// Làm mới trang trong trình duyệt web sẽ thiết lập một kết nối SSE mới, nhưng chỉ có kết nối cuối cùng mới hoạt động, nên kết nối đã chết phải được đóng ở đây.
fmt.Printf("Lỗi khi xả: %v. Đóng kết nối http.\n", err)
break
}
time.Sleep(2 * time.Second)
}
}))
return nil
})
// Khởi động máy chủ
log.Fatal(app.Listen(":3000"))
}