连接保活
WebSocket 行情推送是长连接服务。客户端需要正确处理 WebSocket 协议层的 ping/pong、网络超时、断线重连,以及重连后的重新鉴权和重新订阅。
WARNING
当前行情推送接口不定义业务层 JSON 心跳消息。请不要向连接发送自定义的 { "action": "heartbeat" }、{ "type": "ping" } 等业务心跳帧,也不要依赖服务端返回某种 JSON 心跳事件。
连接保活应使用 WebSocket 协议层 ping/pong 能力,或使用客户端 SDK / WebSocket 库提供的连接状态、超时和重连机制。
Ping / Pong
WebSocket 协议本身支持 ping/pong 控制帧。不同运行环境的处理方式不同:
| 客户端类型 | 建议 |
|---|---|
| 浏览器 WebSocket | 浏览器会在协议层自动响应服务端 ping。业务代码通常无法直接发送或监听协议层 ping/pong,只需要处理 open、message、error、close 等事件。 |
| Node.js、Java、Go、Python 等服务端客户端 | 优先使用 WebSocket 库内置的 ping/pong、读写超时和空闲检测能力。收到服务端 ping 时应及时返回 pong;如客户端库需要主动 ping,可按业务网络环境配置。 |
| 移动端或弱网络环境 | 关注前后台切换、网络切换、系统省电策略导致的连接挂起。恢复网络后应检查连接状态,必要时重连。 |
平台不要求客户端发送某个固定 JSON 格式的心跳包。若你的 WebSocket 库支持协议层 ping,可以开启库自带的 ping/pong 机制;若运行环境不暴露协议层 ping,则应通过连接关闭事件和业务消息超时来判断连接是否可用。
定时刷新 Token
OAuth 2.1 签发的 Access Token 有有效期限制。为避免 token 过期导致连接被服务端主动断开,客户端应在 token 到期前定时刷新:
- 在获取 token 时记录
expires_in(有效期秒数)。 - 建议在 token 有效期过半或到期前 5 分钟时,使用 Refresh Token 获取新的 Access Token。
- 获取新 token 后,通过当前 WebSocket 连接重新发送登录鉴权消息,完成 token 更新。
- 如果刷新失败(例如 Refresh Token 也已过期),应引导用户重新授权。
TIP
定时刷新 token 是长连接保活的关键步骤。即使网络和 WebSocket 协议层 ping/pong 一切正常,token 过期后服务端仍会断开连接。
超时处理
长连接可能因为以下原因断开或变得不可用:
- 本地网络切换、代理或防火墙中断连接。
- 客户端进程休眠、移动端进入后台、系统回收网络资源。
- 服务端发布、扩缩容或维护。
- 连接长时间无有效读写,被中间链路或 WebSocket 库判定为空闲超时。
建议客户端实现以下超时策略:
- 连接建立超时:发起连接后,如果在合理时间内未进入
open状态,应关闭本次连接并重试。 - 鉴权响应超时:连接建立后需要先完成登录鉴权。如果鉴权请求长时间没有响应,应关闭连接并重新建立。
- 订阅响应超时:订阅请求发出后,如果长时间未收到响应,应结合连接状态决定是否重试订阅或重连。
- 业务消息空闲检测:如果连接处于打开状态但长时间没有任何消息,应结合协议层 ping/pong、行情时段和订阅标的活跃度判断连接是否仍然健康。不要仅因非交易时段没有行情推送就立即判定连接失效。
具体超时时间请按客户端所在网络环境、产品实时性要求和 WebSocket 库能力设置。文档不承诺固定的公网 ping 间隔或超时阈值。
断线重连
收到 close 事件、连接异常、鉴权失败、订阅链路不可用或本地检测到连接失效时,客户端应重新建立 WebSocket 连接。
推荐重连流程:
- 停止向旧连接发送新请求。
- 清理旧连接的本地状态,例如正在等待响应的请求、连接对象、临时定时器等。
- 使用退避策略重新连接,避免短时间高频重试。
- 连接建立后重新登录鉴权。
- 鉴权成功后重新订阅当前业务仍然需要的标的和数据类型。
- 订阅恢复后,按需通过 REST 实时行情接口补齐最新状态。
建议使用指数退避或分段退避策略,例如首次断线后较快重试,连续失败后逐步增加等待时间,并设置最大重试间隔。不要在网络不可用或服务端持续拒绝时无限高频重连。
重新鉴权与重新订阅
WebSocket 订阅状态与当前连接会话相关。连接断开后,不应假设服务端仍然保留旧连接上的订阅状态。
每次重连后都应按以下顺序恢复:
建立 WebSocket 连接
-> 登录鉴权
-> 订阅 quote / order_book / ticker / kline 等数据
-> 接收推送注意事项:
- 重连后必须重新鉴权。不要复用旧连接的会话状态。
- 重连后必须重新发送订阅请求。客户端应在本地维护“当前业务需要订阅什么”,而不是依赖服务端恢复。
- 如果访问凭证已经过期,应先刷新凭证,再重新建立连接或重新鉴权。
- 如果重连期间用户已经离开页面或取消关注某些标的,不要恢复这些不再需要的订阅。
- 订阅请求建议携带客户端生成的请求
id,便于将响应与本地待恢复任务对应起来。
结合 REST 获取首屏快照
WebSocket 推送更适合接收实时变化,不适合作为首屏完整状态的唯一来源。为了减少首次渲染等待时间,并避免在断线期间遗漏最新状态,建议在以下场景结合 REST 实时行情接口:
| 场景 | 推荐做法 |
|---|---|
| 页面首次打开 | 先调用 REST 获取行情快照或实时报价,快速渲染首屏;随后建立 WebSocket 连接并订阅实时推送。 |
| 断线重连成功后 | 使用 REST 查询最新快照、买卖盘、当前 K 线或逐笔成交,再继续消费 WebSocket 推送。 |
| 长时间后台后恢复 | 先检查连接是否仍然有效;如果发生重连,建议用 REST 补齐恢复时刻的最新状态。 |
| 对完整状态一致性要求高 | 以 REST 查询结果作为某一时点的完整状态基线,再用 WebSocket 推送增量刷新。 |
相关 REST 接口可参考:
服务端会话清理
连接断开后,服务端会在后台识别离线连接并清理对应会话和订阅资源。该清理过程是服务端内部保护机制,用于释放离线连接占用的资源。
客户端不应依赖服务端清理时机来管理自身订阅状态:
- 正常退出页面、切换标的或不再需要某类数据时,应主动发送反订阅请求。
- 连接异常断开时,客户端应按重连流程重新鉴权并重新订阅,而不是等待旧会话恢复。
- 不要假设旧连接上的订阅会在新连接中自动继承。
- 不要依赖服务端会话清理完成后才重新订阅;新连接应作为新的独立会话处理。
客户端实现建议
建议客户端维护一份本地订阅意图表,用于记录当前业务真正需要的订阅项:
symbol + data_type + 可选参数(如 kline period / adjust)连接恢复时,根据这份订阅意图表重新发送订阅请求。这样可以避免以下问题:
- 断线后忘记恢复部分订阅。
- 用户已经取消关注后仍然恢复旧订阅。
- 多个页面或模块重复订阅同一标的,导致本地状态混乱。
- 重连过程中无法区分哪些订阅响应对应当前连接。
同时建议:
- 将连接状态展示给用户,例如“连接中”“实时行情已连接”“正在重连”。
- 对连续重连失败设置告警或用户提示。
- 对订阅失败、权限不足、配额不足等业务错误进行独立处理,不要简单地无限重连。
- 页面关闭、组件卸载或业务不再需要时,主动反订阅并关闭连接。
常见误区
| 误区 | 说明 |
|---|---|
| 发送 JSON 心跳包即可保活 | 行情推送不定义业务层 JSON 心跳协议。应使用 WebSocket 协议层 ping/pong 或客户端库的连接保活能力。 |
| 断线后订阅会自动恢复 | 不应这样假设。重连后应重新鉴权并重新订阅。 |
| 有 WebSocket 推送就不需要 REST | WebSocket 适合实时变化;首屏完整状态、断线补齐和一致性校准仍建议结合 REST。 |
| 没有行情推送就是连接断了 | 非交易时段、标的不活跃或订阅类型本身更新频率低时,可能长时间没有业务推送。应结合协议层心跳和连接事件判断。 |
| 服务端清理旧会话后客户端才能重连 | 客户端可以直接建立新连接并恢复订阅。服务端会自行清理离线会话资源。 |