用 abort 中断 AI 流式请求,我之前做错了

"停止生成"这个按钮,看着简单,我第一版做得是错的------点了停止,前端是不显示了,但请求还在后台跑,后端还在生成,token 照烧。后来认真用 AbortController 重做了一遍,把正确姿势和坑记下来。

错误示范:只 cancel reader

我最早是这么写的:

scss 复制代码
// 错误!
reader.cancel()

reader.cancel() 确实停止了前端读流,但底层的 HTTP 请求不一定真的断,后端可能还在往一个没人读的连接里写。看着停了,其实没省。

正确做法:AbortController

把 signal 传给 fetch,中断时调 abort(),整个请求(包括底层连接)才真断:

php 复制代码
const controller = new AbortController()
const res = await fetch('/api/chat', {
  signal: controller.signal,
  method: 'POST',
  body: JSON.stringify({ messages }),
})
// 用户点停止:
controller.abort()

abort() 会让 fetch 抛一个 AbortError,记得 catch 住,别让它当成真错误弹报错给用户:

kotlin 复制代码
catch (e) {
  if (e.name === 'AbortError') return // 用户主动停的,正常
  showError(e)
}

坑一:abort 后状态没清干净

中断后,那条"正在生成"的消息可能停在半句话。我得决定:是保留半句(用户可能就想要这点),还是整条删掉。我选了保留,但在末尾标个"(已停止)",不然用户以为是完整回答。

坑二:abort 和新请求打架

用户停了上一条,马上又发新的。如果没把旧 controller 置空,新请求复用了旧的 signal(已经 aborted),新请求一发就直接被 abort,整个对话框"卡死"。我吃过这亏。每次发新消息都 new 一个全新的 controller:

csharp 复制代码
let controller
function send() {
  controller = new AbortController() // 每次都新建
  ...
}

坑三:组件卸载也该 abort

用户在生成中途切走了页面/关了对话框,组件卸载时也得 abort(),不然请求成了野请求,回调还可能往已销毁的组件里 set state 报警告。在卸载钩子里统一收尾。

没做到位的

abort 我只断了前端,后端是否真的因为连接断开就停止计费,得看后端实现。理想是前端 abort 时再显式发个取消信号给后端,双保险。这块我跟后端还没对齐,暂时只信连接断开这一层。

模型用的讯飞 MaaS,现成 API,连接断了那边的计费逻辑省心,前端把中断这套做严谨就行。你们 abort 还遇到过啥坑,评论区交流。

相关推荐
苍何7 小时前
开源微信流 Windows,微信聊天记录,可以直接给 Codex 和 Obsidan 了
后端
代码什么用8 小时前
Spring基础使用
java·后端·spring
明月_清风9 小时前
Deno 终局来了:从挑战 Node 到被 Cloudflare 收编
前端·后端·node.js
蜗牛互联网9 小时前
Java 17 HttpClient调用文件转写API的超时与失败回退
java·人工智能·后端
用户693717500138412 小时前
2026,程序员的时代拐点到了
android·前端·后端
惜鸟12 小时前
从源码看 pi 的上下文管理:原始数据永久保留,模型视角按需裁剪
后端
量化分析码农12 小时前
【Python量化策略评估体系 #05】极端行情扛得住吗?2008/2015/2020 三场景压力测试
后端
十年Java程序媛12 小时前
Java 接口和抽象类对比|Java8 新特性,抛弃老旧八股,正确选型
java·spring boot·后端
IT_陈寒12 小时前
SpringBoot自动配置差点让我加班到凌晨
前端·人工智能·后端
用户83562907805112 小时前
使用 Python 对 Excel 工作表进行排序
后端·python