DEBUG.WIKI
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
RackNerd;$21.99/年 · 1GB KVM
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Ky 空响应下载完成,进度条却停在 0

Ky 2.0.2 的空 200 响应流可能缺少最终下载进度事件。区分响应头到达、正文读完和进度回调,核对正式版本后修正完成状态。

下载接口返回 200,Content-Length: 0,请求已经结束,界面的进度条却一直停在 0。若界面只等 onDownloadProgress 的 percent: 1 才退出 loading,需要同时检查 Ky 版本和正文是否真的被消费。

Ky 2.0.2 的进度转换流,只在读到过数据块时发送最后的完成事件。对于确实存在但没有数据块的空响应流,内部 previousChunk 一直是 undefined,结束时就跳过了回调。

先分清等待的是哪一步

await ky.get(...) 返回 Response,并不代表调用方已经把响应正文读完。进度计算发生在流被读取的过程中;只等响应头、却从不消费 body,不能要求下载进度自然走到末尾。

下面用 arrayBuffer 明确等待正文读取完成。/api/export 代表应用自己的无副作用下载入口,updateProgress、markComplete、markFailed 是界面函数:

import ky from 'ky';

async function loadExport() {
  try {
    const bytes = await ky.get('/api/export', {
      onDownloadProgress: ({ percent }) => {
        updateProgress(percent);
      },
    }).arrayBuffer();
    markComplete(bytes);
  } catch (error) {
    markFailed(error);
    throw error;
  }
}

这里将成功读取正文作为界面完成的依据,回调负责显示中间进度。网络中断、取消或正文读取失败时走失败分支,不能在 finally 中无条件把进度标成成功。读取为 arrayBuffer 会把结果保存在内存中;大文件应沿项目原有的流式保存路径消费,不能为了进度条强行改成全量缓存。

空 200 的旧缺陷已有正式实现对照

正式 Ky 2.2.0 的 flush 会把缺省的最后一个数据块替换为空 Uint8Array,再发送 percent 为 1 的事件。它不再要求 previousChunk 存在,能够覆盖有响应流但零数据块的结束路径。

因此,实际使用 2.0.2 且命中这个条件时,可以沿项目的兼容升级流程核对包含这一处理的正式版本。应检查部署产物解析到的实际版本,而不是只看 package.json 的范围;这里不据两个版本的对照推定最早修复版本。

没有 body 的响应是另一类情况。204、HEAD 等请求可能根本不经过进度包装,不宜把每次成功都定义为“必须收到一个下载回调”。完成状态仍应来自所需业务操作已经结束。

不要根据 Content-Length 为零就跳过所有正文读取。该头可能缺失、不准确或受传输方式影响;也不能在任意请求收到 Response 时直接设置 100%,那会把尚未读完的大响应提前标记为成功。

验收时至少覆盖空 200、有内容的 200、无正文的 204,以及中途取消。检查空文件是否按接口契约被接受、实际读取是否结束、进度是否回退,以及失败时按钮和 loading 是否恢复。这里的修订解决下载状态表达,不代表空导出文件在业务上一定有效。