当前位置:首页 > 文章列表 > 文章 > 前端 > WebSocket 怎样区分 close code 与网络断开

WebSocket 怎样区分 close code 与网络断开

来源:17golang原创 2026-10-24 23:17:13 0浏览 收藏

WebSocket 断开时,真正有用的不是只看“触发了 close 事件”,而是一起读取 event.code、event.wasClean 和 event.reason。完成关闭握手通常属于正常关闭;如果底层连接丢失、根本没有收到 Close 帧,浏览器会把它归为非正常关闭,常见表现是 code === 1006。

官方资料地址:https://www.rfc-editor.org/rfc/rfc6455#section-7.1.5

判断原则可以压缩成一句话:wasClean 先回答“关闭握手是否完成”,code 再回答“收到的关闭状态是什么”,reason 只是对端附带的可读说明;网络断开不能靠一个自定义 close code 伪装成服务端原因。
要点速览
  • 1006 是本地用于表示异常关闭的保留值,端点不能把它写进 Close 控制帧发送。
  • error 事件通常不给出可依赖的原因文本,最终要在 close 事件里记录分类线索。
  • 清理心跳和旧连接后,只对可恢复的非正常关闭安排退避重连;用户主动离开页面不应继续重连。

先分清 Close 帧与传输断开

WebSocket 的关闭握手由 Close 控制帧开始:一端发送 Close,另一端回应 Close,底层 TCP 连接随后关闭。只有关闭握手已经完成,规范才把这次关闭称为 clean。服务端主动发来 1000、客户端调用 close(1000),都属于“有协议关闭过程”的方向。

网络拔掉、代理超时、进程崩溃或连接在握手阶段失败时,浏览器可能没有收到任何 Close 帧。这时 1006 只是客户端对“异常关闭、没有收到关闭状态”的本地表示,不能据此断言具体是 Wi-Fi、代理还是服务端崩溃。RFC 6455 还明确规定,1005 和 1006 都不能作为端点实际发送的 Close 状态码。

WebSocket Close 帧、关闭握手、底层 TCP 连接与 1006 本地表示的静态关系说明图
图1:结构说明图,查看 Close 帧、关闭握手和传输断开的边界;这是原创静态说明图,不是浏览器截图或运行证据。

用 close 事件保留三个线索

浏览器会在客户端关闭、服务端关闭或发生错误后触发 close。因此不要把 error 处理器当成唯一的断线入口;它更适合记录“曾经发生异常”,真正统一清理和分类应放在 close 里。

let reconnectTimer = null;
let intentionalClose = false;

function attachSocket(socket) {
  // error 通常没有稳定的可读原因,只保留发生过异常这一线索。
  socket.addEventListener('error', () => {
    console.warn('WebSocket transport error');
  });

  socket.addEventListener('close', (event) => {
    // code 是收到的关闭状态;wasClean 判断关闭握手是否完成。
    const report = {
      code: event.code,
      wasClean: event.wasClean,
      reason: event.reason || '',
      abnormal: !event.wasClean || event.code === 1006,
    };
    console.info('WebSocket closed', report);

    // 先清理心跳和旧连接,再决定是否创建新连接,避免多个连接并存。
    stopHeartbeat();
    if (report.abnormal && !intentionalClose) {
      scheduleReconnect();
    }
  });
}

这里的 reason 只能当作对端提供的短文本,可能为空,也不等同于网络层错误描述。日志至少保留时间、连接地址的脱敏标识、code、wasClean、页面状态和是否由本地主动关闭,后续才能和服务端日志对照。

按 code 和 wasClean 分类,而不是只看 1006

分类时先看 wasClean,再按业务关心的代码做细分。1000 一般表示正常完成任务,1001 常用于离开页面或服务端下线,1008 可表示策略限制,1011 可表示服务端遇到未预期条件。它们表达的是关闭握手里携带的协议状态,不是 HTTP 状态码。

一个 clean 关闭也不等于“业务一定成功”:服务端可能在拒绝登录后用自定义的 4000–4999 应用代码完成握手。相反,wasClean === false 也不能直接证明服务端有故障,它只说明客户端没有完成可确认的正常关闭过程。

CloseEvent 的 code、wasClean、reason 与 error 事件分类及重连决策关系图
图2:结构说明图,查看 CloseEvent 三个字段与异常线索、清理和重连边界;这是原创静态说明图,不是运行结果。

把分类接到清理与退避重连

用户点击退出、页面进入 pagehide 或组件卸载时,应先设置本地意图,再调用 close(1000, 'client shutdown') 并停止重连。反之,网络异常导致的非正常关闭,可以使用单一重连定时器和指数退避,避免短时间内创建多个 WebSocket。

function closeByUser(socket) {
  // 先标记主动关闭,close 回调就不会误启动重连。
  intentionalClose = true;
  stopHeartbeat();
  socket.close(1000, 'client shutdown');
}

function scheduleReconnect() {
  // 已经有定时器时不重复排队,避免断线风暴。
  if (reconnectTimer !== null) return;
  reconnectTimer = window.setTimeout(() => {
    reconnectTimer = null;
    intentionalClose = false;
    connect();
  }, 1000);
}

window.addEventListener('pagehide', () => {
  // 页面离开是明确的生命周期信号,不应被当作网络故障重连。
  if (socket) closeByUser(socket);
}, { once: true });

重连策略只回答“是否再次建立连接”,不能替代根因诊断。若日志长期只有 1006,还要把客户端时间点与服务端连接、代理空闲超时、网络切换和页面生命周期记录放在一起比较;若看到稳定的 1008 或应用自定义代码,则先处理认证、权限或业务状态,不要无限重试。

常见问题

看到 1006 能确定是服务端挂了吗?

不能。它表示客户端没有收到 Close 帧或底层连接异常结束,服务端崩溃只是可能性之一,还可能来自代理、网络切换、浏览器生命周期或握手失败。

wasClean 为 true 就不用看 code 了吗?

不用。wasClean 只说明关闭过程是否完整,业务仍需要根据 1000、1008 或应用自定义代码决定提示、登出或重连行为。

为什么 error 里拿不到服务端原因?

WebSocket API 的 error 事件不是稳定的原因载体;应在 close 事件中读取 code、wasClean 和 reason,并结合服务端日志还原网络路径。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
File System Access API 使用 showSaveFilePicker 保存 Blob 文件File System Access API 使用 showSaveFilePicker 保存 Blob 文件
上一篇
File System Access API 使用 showSaveFilePicker 保存 Blob 文件
社会保险 怎样查询跨省转移接续进度
下一篇
社会保险 怎样查询跨省转移接续进度
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    669次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    686次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    733次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    701次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    536次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码