ode助手的bug,已上报

下面这份可以直接复制上报,按标准 issue 模板组织,包含环境、复现步骤、根因定位(含代码位置)和最小修复建议。

 

—

 

# 缺陷报告:ODE 多功能助手 1.6.3 —「继续下载」必然失败(远程探测 HTTP 400 / ECONNRESET)

 

## 一、摘要

 

下载列表中 `downstate` 为「已暂停」或「下载失败」的任务,点击「继续下载」后**必然**在“远程探测”阶段失败,报 `远程探测失败:HTTP 400 Bad Request` 或 `远程探测失败:read ECONNRESET`,文件 0 字节写入。同一条 URL、同一 Cookie 用其他 HTTP 客户端请求可正常返回 `206`。已定位为 `odeContinueByGid` 传递 `downHeaders` 类型错误,复现率 100%。

 

## 二、环境

 

– 系统:Windows 10/11 x64

– 客户端:ODE 多功能助手 **1.6.3**(`%LOCALAPPDATA%\Programs\ODE`)

  – `resources\app.asar`:39,281,615 字节;`background.js`:2,300,756 字节

– 下载引擎:`downloadEngine = “ode”`,`chunkSize = 522240`,`concurrency` 写库为 128(引擎内取 `min(64, …)`)

– 资源:夸克网盘直链多分卷(`dl-pc-zb.drive.quark.cn`),单卷约 4.28 GB

 

## 三、复现步骤

 

1. 通过「解析链接」下载一个多分卷夸克资源;

2. 下载过程中点击「暂停」,或让其因网络波动进入「下载失败」;

3. 在下载列表中点击该任务(前端对「已暂停/下载失败」状态会触发 `continueDown`);

4. 任务立即变为「下载失败」,`downlist.erron` 写入上述错误。

 

**复现率:100%**(本机 10 个任务全部命中;单任务重试、重启客户端后重试均复现)。

 

补充特征:失败瞬间对应 `.ode` 文件的 mtime **完全不变**,说明在打开/写入下载文件之前就已失败,即失败发生在远端探测阶段。

 

## 四、根因定位

 

`background.js` 中 `odeContinueByGid` 将请求头对象序列化为字符串后传入任务:

 

“`js

var a = /* 解析 t.headers 得到的对象 */;

var r = JSON.stringify(a); // r 是字符串

var i = F({ url: t.downurl, downHeaders: r, … }); // ← 传入了字符串

“`

 

构造函数未做类型处理:

 

“`js

var a = e.downHeaders || { “User-Agent”: t };

this.downHeaders = a; // 此处是字符串

“`

 

`_probeAndCheckLink()` 中对该值做 `Object.assign`,字符串被按字符展开:

 

“`js

var a = Object.assign({}, this.downHeaders, { Range: “bytes=0-1” });

“`

 

结果生成了 **2815 个单字符“请求头”**(`0={`、`1=”`、`2=u` …,数量等于 JSON 字符串长度),请求头块远超服务器上限。

 

用 Node.js 复刻该请求,夸克 CDN 返回:

 

“`

HTTP 400 Request Header Or Cookie Too Large

“`

 

**对照组**(同一 URL、同一 UA、同一 Cookie、同一 `Range: bytes=0-1`):

 

| 请求方式 | 结果 |

|—|—|

| Python urllib(正常 headers 对象) | `206`,`Content-Range: bytes 0-1/4284229877` |

| Node https(正常 headers 对象) | `206` |

| Node https(`Object.assign({}, JSON字符串, …)`,即客户端现行为) | `400 Request Header Or Cookie Too Large` |

 

由此可确认:报错并非链接失效、Cookie 过期或网络问题,而是请求头构造错误;`read ECONNRESET` 是同一原因下服务器直接断开连接的另一种表现。

 

## 五、修复建议

 

**最小改动(1 字节):**

 

“`js

– var r = JSON.stringify(a), i = F({ url: t.downurl, downHeaders: r, … });

+ var i = F({ url: t.downurl, downHeaders: a, … });

“`

 

**建议补充的防御性处理**(兼容历史调用路径,避免同类问题):

 

“`js

this.downHeaders = (typeof a === “string”)

  ? (() => { try { return JSON.parse(a) } catch (e) { return {} } })()

  : a;

“`

 

**同时建议修复的关联问题:**

 

1. `_probeAndCheckLink()` 失败后**不重试**(`retryLimit` 仅作用于分片下载),单次探测失败即永久判定「下载失败」;建议探测同样重试 2~3 次并加退避。

2. 重新解析同一资源时会生成 `xxx(1).rar` 新任务,**不复用已有 `.ode`**,导致已下载进度作废并重复占用磁盘(本次多出 16.33 GB 冗余文件)。

3. `downlist.erron` 仅保存状态码,建议附带 request host 与响应体前 200 字节,便于用户侧和开发者定位。

 

## 六、影响面

 

中等偏高。所有 ode 引擎任务只要经历「暂停→继续」或「失败→重试」,都会失败且无法自行恢复;用户只能重新解析链接从头下载(单卷 4.28 GB,进度全丢)。该问题在 1.6.3 稳定复现,建议列为下个版本的高优先级修复。

 

## 七、可附的现场证据

 

– `%APPDATA%\ODE 多功能助手\ODE.db` → `downlist` 表 `id 100~109` 的 `erron` 字段(10 条均为上述两类错误)

– 失败时 `.ode` 文件 mtime 无变化;其头部位图可读出真实进度(27.08% / 96.34% / 96.95% / 97.23%),可用于证明“失败发生在探测阶段、与已下载数据无关”

– `logs\main.log` 无下载相关记录(仅更新器日志),建议后续把引擎 `console.log` 落盘

 

—

 

需要的话我可以再出一版**纯文本(无 Markdown 标记)**的,方便贴到 QQ 群、论坛或工单系统;也可以把 `erron` 那 10 条记录导出成一张表附在报告后面。

回复

我来回复
  • 暂无回复内容

程序应用发布前均会测试是否合理合规,有些小类联网软件后期可能会偷偷增置违规型(黄赌)广告,如有发现请大家及时反馈窝长进行处理,共同监督维护良好的程序应用下载社区!