การแนะนำเกี่ยวกับ Server-Sent Events (SSE)
Server-Sent Events (SSE) เป็นเทคโนโลยีการดึงข้อมูลจากเซิร์ฟเวอร์ที่ช่วยให้ไคลเอนต์ได้รับอัปเดตโดยอัตโนมัติผ่านการเชื่อมต่อ HTTP โดยอธิบายถึงวิธีที่เซิร์ฟเวอร์เริ่มการส่งข้อมูลไปยังไคลเอนต์หลังจากการเชื่อมต่อเริ่มต้นของไคลเอนต์ ซึ่งถูกนำมาใช้เป็นที่นิยมในการส่งอัปเดตข้อความหรือการสตรีมข้อมูลต่อไปให้กับไคลเอนต์ผ่าน API ของ JavaScript ที่เรียกว่า EventSource ไคลเอนต์สามารถใช้ API นี้เพื่อขอ URL ที่เซิร์ฟเวอร์เพื่อรับการสตรีมเหตุการณ์ ใน HTML5 การใช้งานของ EventSource API ได้มีการประมาณระดับมาตรฐานโดย WHATWG ประเภทสื่อสำหรับ SSE คือ text/event-stream
หมายเหตุ: ความแตกต่างที่สำคัญที่สุดระหว่าง SSE และ Websocket คือ SSE เป็นการจัดส่งข้อความจากเซิร์ฟเวอร์ไปยังไคลเอนต์แบบ one-way ในขณะที่ Websocket เป็นการจัดส่งข้อความทางสองทาง บางครั้งเมื่อความต้องการของธุรกิจไม่ซับซ้อนมาก SSE มีการจัดส่งข้อความแบบ one-way เพียงพอ ซึ่งมีความคล้ายคลึงกับเทคโนโลยีที่ใช้ในการสนทนา ChatGPT AI
ตัวอย่างของ Fiber SSE
package main
import (
"bufio"
"fmt"
"log"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/valyala/fasthttp"
)
// จำลองไคลเอนต์ HTML, นี่คือตัวอย่างการไคลเอนต์รับข้อความจากแบ็กเอนด์ผ่าน JS, ในสถานการณ์ธุรกิจจริง ๆ ไคลเอนต์จะดำเนินการนี้
var index = []byte(`<!DOCTYPE html>
<html>
<body>
<h1>SSE Messages</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 = "Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>
`)
func main() {
// Fiber instance
app := fiber.New()
// จำกัด CORS อนุญาตการเข้าถึงจากโดเมนใดก็ได้
app.Use(cors.New(cors.Config{
AllowOrigins: "*",
AllowHeaders: "Cache-Control",
AllowCredentials: true,
}))
// เข้าถึงเส้นทาง / ก่อนอื่นเราจะส่งหน้าเว็บไซต์ไปก่อน ซึ่งอนุญาตให้เว็บไซต์ของฝั่งไคลเอนต์ขออัปเดตข้อความ SSE จากแบ็กเอนด์
app.Get("/", func(c *fiber.Ctx) error {
c.Response().Header.SetContentType(fiber.MIMETextHTMLCharsetUTF8)
return c.Status(fiber.StatusOK).Send(index)
})
// เส้นทางส่งข้อความ SSE
app.Get("/sse", func(c *fiber.Ctx) error {
// ตั้งค่าส่วนหัว http สำหรับ sse โปรดทราบถึง 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")
// เริ่มส่งข้อความ
c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) {
fmt.Println("WRITER")
var i int
// จำลองการส่งข้อความไปให้ไคลเอนต์อย่างต่อเนื่อง
for {
i++
msg := fmt.Sprintf("%d - เวลาคือ %v", i, time.Now())
// ใช้ writer และฟังก์ชัน Fprintf เพื่อส่งข้อความไปยังไคลเอนต์ ในสถานการณ์ธุรกิจจริง JSON text สามารถส่งไปเพื่อความสะดวกในการประมวลผลของไคลเอนต์
fmt.Fprintf(w, "data: ข้อความ: %s\n\n", msg)
fmt.Println(msg)
// Flush ข้อมูลออกไปยังไคลเอนต์
err := w.Flush()
if err != nil {
// การรีเฟรชหน้าเว็บบราวเซอร์จะอยู่การเชื่อมต่อ SSE ใหม่ ๆ แต่เพียงแค่ล่าสุดเท่านั้นที่ยังมีอยู่ ดังนั้นการปิดการเชื่อมต่อที่เสีย โดยเฉพาะึก
fmt.Printf("เกิดข้อผิดพลาดขณะทำ Flush: %v กำลังปิดการเชื่อมต่อ http\n", err)
break
}
time.Sleep(2 * time.Second)
}
}))
return nil
})
// เริ่มเซิร์ฟเวอร์
log.Fatal(app.Listen(":3000"))
}