Ejemplo de WebSocket con Fiber

Basado en el componente de WebSocket de Fasthttp de Fiber, se utiliza el método *fiber.Ctx, como Locals, Params, Query y Cookies. Aquí tienes un ejemplo de cómo usar WebSocket en Fiber.

Nota: Se requiere la versión 1.18 o superior de Go.

Instalación

go get -u github.com/gofiber/fiber/v2
go get -u github.com/gofiber/contrib/websocket

Firma de la Función

func New(handler func(*websocket.Conn), config ...websocket.Config) fiber.Handler {

Configuración

Propiedad Tipo Descripción Valor Predeterminado
Filter func(*fiber.Ctx) bool Define una función para omitir el middleware. nil
HandshakeTimeout time.Duration HandshakeTimeout especifica la duración para completar el handshake. 0 (sin tiempo de espera)
Subprotocols []string Subprotocols especifica los subprotocolos solicitados por el cliente. nil
Orígenes []string Orígenes permitidos basados en el encabezado de Origen. Si está vacío, permite todos los orígenes. nil
ReadBufferSize int ReadBufferSize especifica el tamaño del buffer de E/S para recibir mensajes (en bytes). 0 (tamaño predeterminado)
WriteBufferSize int WriteBufferSize especifica el tamaño del buffer de E/S para enviar mensajes (en bytes). 0 (tamaño predeterminado)
WriteBufferPool websocket.BufferPool WriteBufferPool es el pool de buffers usado para operaciones de escritura. nil
EnableCompression bool EnableCompression especifica si el cliente debería negociar la compresión para cada mensaje (RFC 7692). false
RecoverHandler func(*websocket.Conn) void RecoverHandler es una función de manejo para recuperarse de un pánico. defaultRecover

Ejemplo

package main

import (
	"log"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/contrib/websocket"
)

func main() {
	app := fiber.New()

	app.Use("/ws", func(c *fiber.Ctx) error {
		// Devuelve true si el cliente solicita una actualización al protocolo WebSocket
		if websocket.IsWebSocketUpgrade(c) {
			c.Locals("allowed", true)
			return c.Next()
		}
		return fiber.ErrUpgradeRequired
	})

	app.Get("/ws/:id", websocket.New(func(c *websocket.Conn) {
		// c.Locals se agrega a *websocket.Conn
		log.Println(c.Locals("allowed"))  // true
		log.Println(c.Params("id"))       // 123
		log.Println(c.Query("v"))         // 1.0
		log.Println(c.Cookies("session")) // ""

		var (
			mt  int
			msg []byte
			err error
		)
		for {
			if mt, msg, err = c.ReadMessage(); err != nil {
				log.Println("read:", err)
				break
			}
			log.Printf("recv: %s", msg)

			if err = c.WriteMessage(mt, msg); err != nil {
				log.Println("write:", err)
				break
			}
		}
	}))

	log.Fatal(app.Listen(":3000"))
	// Accede al servidor WebSocket: ws://localhost:3000/ws/123?v=1.0
	// https://www.websocket.org/echo.html
}

Notas sobre el Uso del Middleware de Caché

Si encuentras un error websocket: bad handshake al usar el middleware de caché, utiliza config.Next para omitir la ruta de WebSocket.

app := fiber.New()
app.Use(cache.New(cache.Config{
	Next: func(c *fiber.Ctx) bool {
		return strings.Contains(c.Route().Path, "/ws")
	},
}))

app.Get("/ws/:id", websocket.New(func(c *websocket.Conn) {}))

Consideraciones para usar el middleware de recuperación

Debido a razones de implementación interna, el middleware de recuperación actualmente es incompatible con el middleware de WebSocket. Por favor, utilice config.RecoverHandler para agregar un controlador de recuperación para los puntos finales de WebSocket. Por defecto, la configuración de RecoverHandler se recupera de los panics, escribe la traza de la pila en stderr, y también devuelve una respuesta que contiene el mensaje de panic en el campo de error.

app := fiber.New()

app.Use(cache.New(cache.Config{
    Next: func(c *fiber.Ctx) bool {
        return strings.Contains(c.Route().Path, "/ws")
    },
}))

cfg := Config{
    RecoverHandler: func(conn *Conn) {
        if err := recover(); err != nil {
            conn.WriteJSON(fiber.Map{"customError": "error occurred"})
        }
    },
}

app.Get("/ws/:id", websocket.New(func(c *websocket.Conn) {}, cfg))