Fiber WebSocket Example

Based on the Fiber's Fasthttp WebSocket component, the *fiber.Ctx method is used, such as Locals, Params, Query, and Cookies. Here is an example of using WebSocket in Fiber.

Note: Go version 1.18 and above is required.

Installation

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

Function Signature

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

Configuration

Property Type Description Default Value
Filter func(*fiber.Ctx) bool Defines a function to skip the middleware. nil
HandshakeTimeout time.Duration HandshakeTimeout specifies the duration for completing the handshake. 0 (no timeout)
Subprotocols []string Subprotocols specify the client's requested subprotocols. nil
Origins []string Origins allowed based on the Origin header. If empty, it allows any origins. nil
ReadBufferSize int ReadBufferSize specifies the I/O buffer size for receiving messages (in bytes). 0 (default size)
WriteBufferSize int WriteBufferSize specifies the I/O buffer size for sending messages (in bytes). 0 (default size)
WriteBufferPool websocket.BufferPool WriteBufferPool is the buffer pool used for write operations. nil
EnableCompression bool EnableCompression specifies whether the client should negotiate compression for each message (RFC 7692). false
RecoverHandler func(*websocket.Conn) void RecoverHandler is a handling function for recovering from panic. defaultRecover

Example

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 {
		// Returns true if the client requests an upgrade to the WebSocket protocol
		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 is added to *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"))
	// Access WebSocket server: ws://localhost:3000/ws/123?v=1.0
	// https://www.websocket.org/echo.html
}

Notes on Using Cache Middleware

If you encounter a websocket: bad handshake error while using cache middleware, use config.Next to skip the WebSocket path.

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) {}))

Considerations for using the recovery middleware

Due to internal implementation reasons, the recovery middleware is currently incompatible with the WebSocket middleware. Please use config.RecoverHandler to add a recovery handler for the WebSocket endpoints. By default, the RecoverHandler configuration recovers from panics, writes the stack trace to stderr, and also returns a response containing the panic message in the error field.

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))