“Go WebSocket ws 报无权限” 99% 发生在 HTTP 握手阶段就被服务器拒掉 了,常见原因与排查/修复办法如下,按出现频率排序:
1. 浏览器直接用 file:// 打开页面
Chrome 会把 file://→ws:// 当成跨域,直接 403/400。
解决:把测试页架到 http(s)://localhost:port/xxx.html,再连 ws:///wss:// 即可 。
2. 服务端没配 CheckOrigin(gorilla/websocket 默认拒绝非浏览器同源请求)
解决:升级时显式放行upgrader := websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool { return true }, // 或按域名白名单校验
}
conn, err := upgrader.Upgrade(w, r, nil)

3. 用 wss:// 却监听的是裸 ws://(或反向代理没开 SSL)
浏览器会报 TLS handshake error / Unexpected response code 403。
解决:- 本地快速测试可先改回 ws://;
- 生产环境在 Go 端监听 tls.Listen 或在 Nginx 层做 proxy_pass ws://backend 并打开 SSL 。
4. 认证中间件把请求拦了
典型现象:先 401/403,再打印“请求未携带 token,无权限访问”。
WebSocket 只能在 握手 URL 或头里带凭证,浏览器无法自定义 Authorization 头,常用两种兼容写法:
a) 查询参数 ws://localhost/ws?token=xxx
b) 借助子协议头 Sec-WebSocket-Protocolconst ws = new WebSocket(url, [token]);   // 前端
token := r.Header.Get("Sec-WebSocket-Protocol")
if token == "" || !validateJWT(token) {
    http.Error(w, "Unauthorized", http.StatusUnauthorized)
    return
}
// 必须再把子协议写回,否则浏览器报错
upgrader.Subprotocols = []string{token}
详见 。
5. 反向代理 (Nginx) 缺 Upgrade 头
现象:状态码 400 或 websocket: bad handshake。
解决:在代理配置里加proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

6. 证书/自签名证书被浏览器拦截
首次访问 wss:// 会提示 ERR_CERT_AUTHORITY_INVALID,点“继续前往”后 WebSocket 才能连上;或者把证书导入系统信任区 。
7. 令牌过期或签名错误
控制台出现 code 4001, reason: Unauthorized 就是服务端主动 ws.Close() 掉的,确认生成/校验 JWT 的密钥、过期时间、时区一致,并打开日志打印 claims 调试 。
一句话总结:
先确认页面不是 file:// 打开 → 看是不是 403/401 → 检查 CheckOrigin 和认证中间件 → 确认 ws/wss 与证书匹配 → 再查反向代理头。按上面 1-7 步逐条排除,基本都能定位“无权限”到底是哪一层拦掉了。
 

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐