跳到主要内容
版本: websocket_v1.x.x

WebSocket

Release Discord Test

基于 Fasthttp WebSocket 构建,适用于 Fiber,并可使用如 Locals, Params, QueryCookies*fiber.Ctx 方法。

注意: 需要 Go 1.18 及以上版本

安装

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

签名

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

配置

属性类型描述默认值
过滤器func(*fiber.Ctx) bool定义一个函数来跳过中间件。nil
握手超时time.DurationHandshakeTimeout 指定握手完成的持续时间。0 (无超时)
子协议[]stringSubprotocols 指定客户端请求的子协议。nil
[]string基于 Origin 头部的允许源。如果为空,则允许所有源。nil
读取缓冲区大小intReadBufferSize 指定传入消息的 I/O 缓冲区大小(字节)。0 (使用默认大小)
写入缓冲区大小intWriteBufferSize 指定传出消息的 I/O 缓冲区大小(字节)。0 (使用默认大小)
写入缓冲区池websocket.BufferPoolWriteBufferPool 是用于写入操作的缓冲区池。nil
启用压缩boolEnableCompression 指定客户端是否应尝试协商逐消息压缩(RFC 7692)。false
恢复处理器func(*websocket.Conn) voidRecoverHandler 是一个 panic 处理函数,用于从 panic 中恢复。defaultRecover

示例

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 {
// IsWebSocketUpgrade returns true if the client
// requested 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 the *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")) // ""

// websocket.Conn bindings https://pkg.go.dev/github.com/fasthttp/websocket?tab=doc#pkg-index
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 the websocket server: ws://localhost:3000/ws/123?v=1.0
// https://www.websocket.org/echo.html
}

关于缓存中间件的注意

如果你在使用 缓存中间件 时遇到错误 websocket: bad handshake,请使用 config.Next 来跳过 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) {}))

关于恢复中间件的注意

由于内部实现原因,目前恢复中间件不适用于 websocket 中间件,请使用 config.RecoverHandler 为 websocket 端点添加恢复处理器。默认情况下,config RecoverHandler 会从 panic 中恢复并将堆栈跟踪写入 stderr,同时返回一个包含 panic 消息的响应,该消息位于 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))


关于 WebSocket 子协议的注意

配置中的 Subprotocols 只帮助你协商子协议,并在找到合适的子协议时设置 Sec-Websocket-Protocol 头部。有关协商过程的更多信息,请查阅 fasthttp.UpgraderSubprotocols 的注释。

所有连接都将发送到处理函数,无论子协议协商是否成功。你可以通过 conn.Subprotocol() 获取选定的子协议。

如果连接请求中包含 Sec-Websocket-Protocol 头部但协议协商失败,浏览器在收到升级响应后将立即断开连接。