DEBUG.WIKI
雨云;给项目一台云服务器
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →
PanstarCloud:部署应用,接入 AI,云服务器与 AI 网关

Got 流式请求带 CookieJar 后一直等不到 end

快速响应在等待 CookieJar 写入时结束,旧 Got 流可能错过结束事件。核对正式实现的监听顺序,保留 Cookie 保存、流消费和异常传播。

got.stream() 下载普通响应正常,一加 cookieJar,收到 Set-Cookie 后却一直没有 end。若正文很短、服务器已结束响应,应检查 Cookie 存储的等待过程与结束监听器的注册顺序。

Got 15.0.0 在处理 Set-Cookie 时先等待 CookieJar 的异步写入,随后才注册响应 end 监听器。快速响应可能在等待期间已经读完,后加的监听器收不到过去的事件,外层可读流就无法正常结束。

先排除没有消费流和没有完成的存储

可读流没有被读取时,不能只监听 end 就等待下载完成。调用方应沿原有保存、解析或丢弃路径消费正文,并处理 error。另一方面,自定义 CookieJar 如果 setCookie 永不完成,升级响应监听顺序也不能让这次写入自动结束。

因此,先判断正文是否被消费、CookieJar 的写入 Promise 是否完成、服务端是否确实发送完整响应。不要为诊断打印 Cookie 值;记录状态、时序和必要的非敏感标识即可。

采用提前监听且补查结束状态的正式实现

Got 16.0.0 与 16.1.0 已在等待 CookieJar 前注册 end,并通过 canFinalizeResponse 控制外层结束:既要知道正文已读完,也要等 Cookie 处理完成。后续还会检查 readableEnded,覆盖早已结束的情况。

这为命中旧路径的应用提供了正式升级方向,不据两个版本对照推定最早修复版本。升级前核对运行时和选项兼容,16.1.0 要求 Node 22 或更新。不能把关闭 cookieJar 或忽略所有无效 Cookie 当成修复,那会改变会话和认证行为。

使用流式管道的项目,可保留类似下面的错误传播方式。url、cookieJar、destination 都来自应用现有的已审定配置:

import got from 'got';
import { pipeline } from 'node:stream/promises';

export async function download(url, cookieJar, destination, signal) {
  await pipeline(
    got.stream(url, {
      cookieJar,
      signal,
      timeout: { request: 10000 },
    }),
    destination,
  );
}

一万毫秒是示例时限,需符合实际下载大小与服务策略。destination 必须是本次操作可写的目标流;pipeline 会在结束或失败时处理流生命周期,不适合不希望被结束的共享输出流。这里用它等待完整消费并传递失败,不能用它替代缺陷版本的升级。

若业务不需要正文而选择 resume 丢弃,也要保留 error 和完成处理。不能在收到 response 事件时就认定下载成功:它只表示响应可用,正文与 Cookie 存储可能还没结束。

回归应包括短正文加 Set-Cookie、无 Cookie、较大正文、CookieJar 写入拒绝和中途取消。确认流按预期完成或失败,并检查后续请求使用到的 Cookie;只让外层等待函数提前返回,不能证明会话已保存。