症状
对 AbortController 调用 abort 似乎毫无作用:fetch 的 Promise 仍会 resolve 或继续挂起,请求在网络上继续。signal 存在但常常没有转发进客户端选项,或 abort 在响应对象返回之后、body 仍在读取时触发,于是取消落在不再被观察的阶段。
诊断
用最小示例确认 fetch 的 catch 能打印 AbortError;在读取 body 时触发 abort 观察行为;搜索包装层是否透传 signal。
node -e "const c=new AbortController(); fetch(url,{signal:c.signal}).catch(e=>console.log(e.name)); c.abort()"
根因
AbortSignal 从未到达底层请求,或 abort 发生在客户端不再视为可取消的阶段,因此尽管调用了 abort,请求仍在继续。
修复
把 signal 贯穿所有构造请求的层:直接调用、重试包装与辅助函数。把超时绑定到同一个 controller,使取消与过期共用一条路径,并明确响应头到达后是否仍可取消。
验证
触发 abort 确认请求迅速以 AbortError 拒绝,再确认对端停止接收该请求的数据。客户端拒绝与服务端停止共同证明取消生效。
常见陷阱
把 signal 传给自定义客户端却没实现取消支持,会造成“看似取消实则继续”;需确认底层确实尊重 signal。