切后台回来断线续接:静默超 20 秒就立即探活

举报
yd_296967770 发表于 2026/11/08 23:54:43 2026/11/08
【摘要】 AI 对话小程序切后台回来输出停住,多半是连接半开。这篇记录对话页的断线续接做法:onHide 记时间、onShow 回来先探活,静默超 20 秒(心跳约 16 秒)立即续接;看门狗兜底断网,delta 追加式拼字保证续上后不丢字、不重复。

做 AI 对话小程序时,有个场景几乎每天都会遇到:AI 正在流式输出,用户切出去回个微信、或者点开图片预览一下,回来发现输出停了,页面还显示“生成中”,要等很久才报错,或者干脆卡住不动。这篇文章记录一下我们对话页是怎么处理“切后台回来断线续接”的:核心就三招——切走时记时间、回来先探活、续上后接着拼字。

问题出在哪:连接“半开”了

先说一个容易误解的点:手机切后台,网络连接不一定立刻断。很多时候 TCP 连接表面上还在,但中间某个环节已经把它丢了,服务器发来的数据到不了手机,手机也不知道对方没了——这就叫“半开连接”。页面还以为自己连着,于是一直等,等不到数据也不报错,用户看到的就是输出停在半截。

所以不能只靠“等报错”,得主动判断:我有多久没收到数据了?

我们的服务端大约每 16 秒发一次心跳——可能是一个空事件或注释行,作用只有一个:证明“我还活着”。客户端每次收到任何数据就重置计时器。心跳正常,说明连接是活的;心跳停了,说明连接可能已经半开了。

第一招:onHide 记时间,onShow 回来探活

小程序页面有两个生命周期钩子,正好对应“切走”和“回来”:

  • onHide:切到后台时,记下当前时间;
  • onShow:切回前台时,如果 _stream 还在(说明上一轮生成还没结束),就调 checkAlive(20000) 主动探活,问一句“你还活着吗”。

判断标准是静默是否超过 20 秒:服务端心跳约 16 秒一次,20 秒没收到任何数据,基本可以判定连接已经半开,不用再等,直接续接。20 秒这个数是留了余量的——比一次心跳间隔稍长,避免心跳稍微抖动一下就误判。

这里有个细节值得一提:预览图片、选素材也会触发 onHide / onShow。但那时心跳是正常的,回来一探活发现连接没事,checkAlive 不会打断连接,该干嘛干嘛。这个判断是按“静默时长”做的,不是按“切过后台”做的,所以短暂切出去不会误伤正在进行的生成。

第二招:看门狗兜底,断网时给用户一个说法

探活解决的是“切后台回来”这个场景,断网本身还有一层兜底:客户端有个看门狗定时器,一直在轮询“距离上次收到数据过去多久了”。超过阈值(比如 30 秒),就判定连接已死,走重连流程。

重连时页面会显示状态条“网络波动,正在重连”,后面还带一个 attempt 计数,告诉用户这是在第几次尝试。收到正常事件的第一时间就把这个状态清掉——onAgentEvent 的第一行就是清 reconnecting,靠的还是“收到任何数据就说明活着”这个判断。

这两层是互补的:checkAlive 是回来时主动问一句,不等看门狗慢慢发现;看门狗是全程盯着,兜住那些没有切后台、纯粹是网络抖动的情况。

第三招:续上后接着拼,不丢字

续接本身不难,难的是“续上之后不丢字、不重复”。

我们的 AI 输出是追加式的:服务端不攒全文,而是一点一点推送事件,前端每收到一小段 delta 就往 AI 气泡里追加显示,这就是看到的“打字机效果”。中途断网时,已经显示的字保留在消息文本里;重连后服务端从断点继续发 delta,前端继续往后追加。

具体到实现,收到的 delta 先攒进 _pendingText,再由 flushDeltas 拼到消息的 text 后面。追加式设计的好处是:续接不需要“把整段重发一遍再比对”,只要从断点继续往后拼,前面已经显示的内容一动不动,既不会丢字,也不会出现重复段落。

打开历史会话时也是同一套思路:如果 runs 里有 status === 'RUNNING' 的轮次,直接调 resumeAgentRun(runId, 0, handlers) 续上这个 run 继续收流,用的还是同一组 handlers——收事件、分发、收尾、报错、重连提示,一个都不用换。

小结

切后台断线续接,表面上是个“重连”功能,实际上是三个判断拼起来的:

  1. 什么时候探活:切回来时看静默时长,超 20 秒(一次心跳约 16 秒)就立即探活,不等看门狗;
  2. 怎么让用户知道:重连时显示“网络波动,正在重连”加 attempt 计数,收到数据立刻清除;
  3. 续上后怎么办:delta 追加式拼字,断点续发,不丢字也不重复。

三个数字可以当作参考:心跳约 16 秒、探活阈值 20 秒、看门狗阈值约 30 秒。它们分工不同:心跳是“活着的证明”,20 秒是“回来时立刻判断的线”,30 秒是“全程兜底的线”。做这类功能,与其纠结重连写得多优雅,不如先把“怎么知道它死了”想清楚——判断准了,重连只是顺手的事。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。