WebSocket跨域时Cookie为空是因浏览器默认不携带,须同源或前后端协同配置credentials与CORS:前端页面启用凭证模式,服务端返回Access-Control-Allow-Credentials:true且Origin精确匹配,并在upgrader.Upgrade()前读取req.Cookies()校验。

WebSocket跨域时Cookie为空的典型现象
浏览器控制台没报错,但服务端 req.headers.cookie 始终是 undefined 或空字符串;Node.js 的 ws 库中 verifyClient 钩子里取不到 session_id;Gorilla WebSocket 的 upgrader.Upgrade() 前读 req.Cookies() 返回空切片。这不是服务端漏解析,而是客户端根本没发——跨域场景下,浏览器默认不携带 Cookie。
必须显式启用 credentials 才能传 Cookie
前端 WebSocket 构造函数不支持传配置对象(如 { withCredentials: true }),这是常见误解。实际生效方式只有两种:
- 同源连接:页面地址(
https://app.example.com)与 WebSocket 地址(wss://app.example.com/ws)完全同域(协议+域名+端口一致),此时浏览器自动携带匹配的 Cookie,无需额外代码 - 跨域连接:必须确保页面和服务端都满足以下条件:
– 前端调用new WebSocket("wss://api.example.com/ws")时,所在页面已启用凭证模式(即页面本身是通过fetch或XMLHttpRequest带credentials: "include"加载的)
– 服务端响应握手请求时,必须返回Access-Control-Allow-Credentials: true
–Access-Control-Allow-Origin不能为*,必须精确匹配前端 origin(如https://localhost:3000)
Gorilla WebSocket 中读 Cookie 的正确时机和写法
很多人在 upgrader.Upgrade() 调用之后才尝试读 Cookie,这时已经晚了——协议升级完成,*http.Request 不再可用。正确做法是在 Upgrade 之前、仍处于标准 HTTP 请求阶段时处理:
func wsHandler(w http.ResponseWriter, r *http.Request) {
// ✅ 此处 r 是完整 *http.Request,可安全读 Cookie
cookies, err := r.Cookies()
if err != nil || len(cookies) == 0 {
http.Error(w, "Missing cookie", http.StatusUnauthorized)
return
}
var sessionID string
for _, c := range cookies {
if c.Name == "session_id" {
sessionID = c.Value
break
}
}
if sessionID == "" {
http.Error(w, "Invalid session", http.StatusUnauthorized)
return
}
// ✅ 校验通过后,再交给 Upgrader
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
defer conn.Close()
}
注意:Gorilla 的 Upgrader.CheckOrigin 默认拒绝所有跨域,若需跨域,必须显式设为 func(r *http.Request) bool { return true }(生产环境应校验 r.Header.Get("Origin"))。
Cookie 属性不匹配导致“发送了却收不到”
即使启用了 credentials,服务端仍收不到 Cookie,大概率是 Cookie 自身属性不兼容:
-
Secure缺失:使用wss://时,Cookie 必须带Secure标志,否则浏览器拒绝发送 -
SameSite过严:跨域 WebSocket 握手属于“跨站请求”,若 Cookie 设为SameSite=Strict,会被拦截;推荐设为SameSite=Lax(同站宽松)或SameSite=None; Secure(跨站必需配 Secure) -
Domain和Path不匹配:比如 Cookie 的Domain=example.com,但 WebSocket 地址是wss://api.example.com,此时需确保Domain包含子域(即设为.example.com)
最易被忽略的一点:服务端在返回 101 Switching Protocols 前,不能有任何重定向(302/307)。一旦重定向,原始 Cookie 就丢失了,后续握手请求不会自动补上。


















