Introducción a Server-Sent Events (SSE)
Los Server-Sent Events (SSE) son una tecnología de servidor push que permite a los clientes recibir automáticamente actualizaciones del servidor a través de una conexión HTTP. Describe cómo el servidor inicia la transferencia de datos al cliente después de establecer la conexión inicial. Comúnmente se utilizan para enviar actualizaciones de mensajes o transmisiones continuas de datos a clientes de navegadores, con el objetivo de mejorar las transmisiones locales a través de la API de JavaScript llamada EventSource. Los clientes pueden usar esta API para solicitar una URL específica y recibir transmisiones de eventos. Como parte de HTML5, la API EventSource ha sido estandarizada por WHATWG. El tipo de medio para SSE es text/event-stream.
Nota: La mayor diferencia entre SSE y Websocket es que SSE es un envío unidireccional de mensajes del servidor al cliente, mientras que Websocket es un envío bidireccional de mensajes. A veces, cuando los requisitos comerciales no son tan complejos, el envío unidireccional de mensajes de SSE es suficiente. Esto es similar a la tecnología utilizada en las conversaciones de inteligencia artificial de ChatGPT.
Ejemplo de SSE con Fiber
package main
import (
"bufio"
"fmt"
"log"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/valyala/fasthttp"
)
// Simular cliente HTML, aquí tienes un ejemplo del frontend recibiendo mensajes push del backend en JS. En escenarios comerciales reales, el frontend implementará esto.
var index = []byte(`<!DOCTYPE html>
<html>
<body>
<h1>Mensajes 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 = "Lo siento, tu navegador no es compatible con los eventos enviados por el servidor (SSE)...";
}
</script>
</body>
</html>
`)
func main() {
// Instancia de Fiber
app := fiber.New()
// Restricciones CORS, permitiendo acceso desde cualquier dominio
app.Use(cors.New(cors.Config{
AllowOrigins: "*",
AllowHeaders: "Cache-Control",
AllowCredentials: true,
}))
// Accede a la ruta /, primero devolvemos la página frontend, permitiendo al frontend solicitar al backend iniciar el envío de mensajes SSE
app.Get("/", func(c *fiber.Ctx) error {
c.Response().Header.SetContentType(fiber.MIMETextHTMLCharsetUTF8)
return c.Status(fiber.StatusOK).Send(index)
})
// Dirección de envío de mensajes SSE
app.Get("/sse", func(c *fiber.Ctx) error {
// Establecer encabezado http sse, presta atención a 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")
// Comenzar a enviar mensajes
c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) {
fmt.Println("ESCRITOR")
var i int
// Simular el envío continuo de mensajes al cliente
for {
i++
msg := fmt.Sprintf("%d - la hora es %v", i, time.Now())
// Utilizar writer y la función Fprintf para enviar mensajes al cliente, en escenarios comerciales reales, se puede enviar texto JSON para facilitar el procesamiento del frontend
fmt.Fprintf(w, "data: Mensaje: %s\n\n", msg)
fmt.Println(msg)
// Limpiar los datos de salida al cliente
err := w.Flush()
if err != nil {
// Actualizar la página en el navegador web establecerá una nueva conexión SSE, pero solo la última estará activa, por lo que aquí se deben cerrar las conexiones inactivas.
fmt.Printf("Error al limpiar: %v. Cerrando la conexión http.\n", err)
break
}
time.Sleep(2 * time.Second)
}
}))
return nil
})
// Iniciar servidor
log.Fatal(app.Listen(":3000"))
}