websocket握手时无法读取authorization头是浏览器限制,因new websocket()不支持自定义请求头,authorization等字段会被静默丢弃;可用token传递方式仅有url参数或sec-websocket-protocol头,且鉴权必须在upgrade响应前通过中间件完成。

WebSocket握手时无法读取Authorization头是浏览器限制,不是Fiber配置问题
浏览器原生 new WebSocket() 构造函数不支持传自定义请求头,Authorization、X-Token 等字段会被静默丢弃。抓包会发现这些 header 根本没发出,后端收不到不是中间件漏读,是前端压根发不出来。这个限制在 Chrome/Firefox/Safari/Edge 全系生效,和 Fiber 版本、Go 版本无关。
Fiber中间件里只能从URL参数或Sec-WebSocket-Protocol提取token
Fiber 的 WebSocket 握手本质是 HTTP Upgrade 请求,中间件能访问到 c.Request(),但仅限于标准字段。可用的 token 传递路径只有两条:
- URL 查询参数:如
wss://api.example.com/ws?token=xxx,用c.Query("token")读取 -
Sec-WebSocket-Protocol头:浏览器允许客户端设置该字段,值形如"auth-v1;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",需用c.Get("Sec-WebSocket-Protocol")提取并解析
注意:Sec-WebSocket-Protocol 是协议级字段,不是业务头,服务端必须在 Upgrade 响应中回写相同值才能完成握手,否则连接会建立但 ws.protocol 为空——这是静默失败,极易被忽略。
鉴权必须在Upgrade响应前完成,不能放到WebSocket handler里
Fiber 中 WebSocket 连接由 websocket.New() 或 websocket.Upgrade() 触发,但中间件执行时机在 HTTP 请求阶段。如果把 token 校验逻辑放在 websocket.Handler 内部(比如 onOpen 回调),就已错过握手拦截点,非法连接早已建立。
正确做法是:
- 在路由中间件中提前校验 token,校验失败直接
c.Status(401).SendString("unauthorized") - 校验成功后,把用户 ID 或 claims 存入
c.Locals,供后续 WebSocket handler 使用 - 确保中间件注册在
websocket.New()路由之前,例如:app.Get("/ws", authMiddleware, websocket.New(...))
别试图在 websocket.Handler 里调 c.Request().Header.Get("Authorization") —— 它永远是空的。
用URL参数传token要防泄露,Sec-WebSocket-Protocol更安全但需协议对齐
URL 参数方案简单,但 token 会出现在 Nginx 日志、浏览器历史、CDN 缓存、代理记录中,必须强制 HTTPS,且建议配合短期有效期(如 5 分钟)和一次性使用(校验后立即失效)。
Sec-WebSocket-Protocol 方案更干净,但要注意:
- 客户端必须按规范拼接,例如:
new WebSocket("wss://...", ["auth-v1;"+token]) - 服务端解析时要按分号分割,取第二段作为 token,第一段作为协议标识
- Upgrade 响应中必须显式调用
upgrader.Upgrade(c.Context(), w, r, map[string][]string{"Sec-WebSocket-Protocol": {"auth-v1"}}),否则浏览器认为协议不匹配
真正容易被忽略的是:Fiber 默认的 websocket.New() 不暴露底层 http.ResponseWriter 和 *http.Request,你得自己用 websocket.Upgrade() 才能控制响应头和协议回写——这点文档极少提,但生产环境绕不开。











