浏览器原生 WebSocket 不支持自定义请求头,仅能通过 Sec-WebSocket-Protocol 字段(需 Base64 编码 Token)或反向代理(如 Nginx 注入 Authorization 头)传递鉴权信息,且必须在握手阶段完成校验并拒绝非法连接。

浏览器原生 WebSocket 构造函数不支持传自定义请求头,所谓“在 Header 里传 Token”本质上只有两种可行路径:一种是借道 Sec-WebSocket-Protocol 这个唯一被浏览器允许写入的握手头字段;另一种是绕过原生 API,用 fetch + Response.upgrade() 或服务端代理注入。直接写 headers: { Authorization: '...' } 会静默失败。
为什么 new WebSocket(url, { headers }) 不生效
这是最常踩的坑——开发者照搬 axios 写法,以为 WebSocket 支持同款配置对象。实际上 W3C 规范只定义了两个构造参数:url 和可选的 protocols(字符串或字符串数组),没有 headers 字段。任何试图扩展它的做法(比如用 WebSocket.prototype 拦截)都不可靠,且 Chrome/Firefox/Safari 均不识别。
常见错误现象:
- 控制台无报错,但服务端收不到
Authorization头 - 连接成功,但
beforeHandshake中request.getHeaders().getFirst("Authorization")返回null - 误以为是后端没读对,反复改 Java/Kotlin/Go 的 header 提取逻辑,实则前端根本没发出去
用 Sec-WebSocket-Protocol 传 Token 的实操要点
这是兼容性最好、无需代理、纯前端可控的方案,但有硬性约束:值只能含字母、数字、短横线(-),不能有空格、点、下划线、@、中文等。JWT 直接塞进去大概率 400。
正确做法:
- 前端先对 Token 做 URL-safe Base64 编码(去掉
+、/、=,换为-和_),例如用token.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '') - 创建连接时传入单元素数组:
new WebSocket('wss://api.example.com/ws', [encodedToken]) - 后端必须原样回传该值到响应头:
response.addHeader("Sec-WebSocket-Protocol", receivedProtocol),否则浏览器会关闭连接 - 后端从
request.getHeaders().getFirst("Sec-WebSocket-Protocol")取值,再做 Base64 解码还原 JWT
注意:Sec-WebSocket-Protocol 是协商字段,不是任意键值对容器;如果后端校验失败,应直接拒绝握手(返回 401 或 403),而不是等连接建立后再关掉。
服务端代理注入 Authorization 头的现实路径
如果你控制 Nginx 或 Cloudflare,这是生产环境更推荐的方式:前端仍用最简 URL 连接,鉴权头由反向代理统一添加。
Nginx 配置关键项:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
location /ws {
proxy_pass https://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Authorization "Bearer $cookie_x_token"; # 从 Cookie 提取
# 或 proxy_set_header Authorization "Bearer $arg_token"; # 从 URL 参数提取
}这样前端代码干净:new WebSocket('wss://your-domain.com/ws?token=xxx'),Nginx 把 ?token=xxx 或 Cookie: x_token=xxx 转成标准 Authorization: Bearer xxx 头发给后端。后端就可走常规 JWT 校验流程,无需适配子协议解析逻辑。
限制:
- 需要运维配合改网关配置,前端无法独立完成
- 若用 Cookie 传 Token,需确保 WebSocket 请求同源,且 Cookie 标记了
SameSite=None; Secure - URL 参数方式虽简单,但 Token 会出现在 access log、CDN 缓存、浏览器地址栏历史中,敏感场景慎用
Hoppscotch 和 Python 客户端怎么填 Token
工具和脚本不受浏览器限制,可以真正发自定义头。
Hoppscotch:
- 选 WebSocket 协议,URL 栏填完整带参地址,如
wss://api.example.com/ws?token=eyJhbGciOi... - 不填额外 header —— 它不支持在 WebSocket 模式下设请求头
- 若服务端只认
Authorization头,Hoppscotch 就不适用,得换websocat或写 Python 脚本
Python(websocket-client 库):
from websocket import create_connection
headers = ["Authorization: Bearer " + token]
ws = create_connection("wss://api.example.com/ws", header=headers)注意:Bearer 后必须跟一个空格,Token 本身不要 URL 编码;服务端收到的是原始字符串,不是 %xx 形式。
真正难的不是“怎么传”,而是“谁来校验、什么时候校验、校验失败怎么关”。所有方案都必须把鉴权逻辑卡死在握手阶段(beforeHandshake 或 onUpgrade),绝不能放行未鉴权连接再消息级校验——那等于开门揖盗。

















