Repository navigation
feat(drivers): 下载链接随附 UA / Referer,并让 123 默认走直链 - #120
wumingzhinu wants to merge 1 commit into
Conversation
5909544 to
57fe1ce
Compare
57fe1ce to
cf411de
Compare
## 动机
原先是「服务端替客户端搬字节」的形态:Worker 用 `raw_url_headers` 取回 CDN
内容再转发。在 Cloudflare Workers 上这条路有三个固定代价:
1. **客户端只能单线程下** —— Worker 是唯一出口,多线程分片无从谈起;
2. Worker 吃满 CPU / 子请求预算(代码里可见 SUBREQUEST_LIMIT 之类常量);
3. 受平台响应体上限约束,超限还得降级回 302。
参考 YunX:同一批直链在客户端可开 32~512 线程(迅雷锁 8)。
要吃到这个能力,就必须把直链连带 UA/Referer 交给客户端。
## 改动一:四个驱动的取链函数返回请求头
`Promise<string>` → `Promise<{ url, headers }>`,驱动赋给 `raw_url_headers`。
| 驱动 | 新增头 | 依据 |
| --- | --- | --- |
| 115 | User-Agent | 同族 115open 同一约定(UA 绑进取链请求) |
| quark_uc_tv | Referer + UA | 同族 quark 已返回 {url, headers} |
| 123pan | Referer + UA | YunX Pan123Api 注明 CDN 直链需 Referer |
| 123_open | Referer + UA | 同上,同一 CDN 体系 |
## 改动二:`123pan` / `123open` 移出 `DRIVER_PREFER_PROXY`
这张表决定**新建存储时 `web_proxy` 的默认值**:命中即默认勾选,即默认由
Worker 代理字节 —— 客户端拿不到直链,多线程无从发生。
移出后默认改为 302 直链。依据是仓库自己的判定:
`server/proxy_request.ts` 的 `PRIVATE_HEADER_NAMES` 只有 authorization /
cookie,其注释明确写着 UA / Referer / Origin「浏览器可以自己提供」,
**不构成必须服务端代理的理由**。
**只影响新建存储的默认值**:已有存储有显式持久化的 `web_proxy`,
`effectiveWebProxy` 优先读显式值,行为不变,管理员可随时勾回。
## 改动三:`/api/fs/link` 接通 `link()` 并返回 headers
排查时发现 **`link()` 是死代码**:10 个驱动实现了它
(115_share、123_share、139、189pc、aliyundrive_share、dropbox、mega、
onedrive_sharelink、pikpak_share、wps),但下载链路里没有任何地方调用。
而 `fs.ts` 的 `/link` 端点只返回 `{url}`,既不调 `link()` 也不回 headers。
后果:多线程下载器**没有任何途径**拿到驱动指定的精确头 —— 302 只能交给
浏览器自带的 UA/Referer,取不到驱动指定的值。这正是「无法让客户端多线程」的
根因之一。
改造 `/api/fs/link`:
- 优先调用驱动 `link()`,成功则直接返回 `{url, headers}`;
- `link()` 不可用或失败时回退 `driver.get()` 的 `raw_url` + `raw_url_headers`;
- `linkOk` 时**跳过** `driver.get()`,省一次上游往返(仓库在意子请求预算)。
安全性:`link()` 返回的头可能含 Cookie / Authorization。该端点本就是
admin-only(上方有 `isAdmin` 判定),受众正是「正在配置下载管理器的管理员」,
原样返回是恰当的。已加测试守住权限门,防止回归成任意用户可取。
## 为什么 `baidu_netdisk` 没一起改
三条 `download_api` 路径都只带 UA(`official` 要求恰为 `pan.baidu.com`)。
百度是否校验 UA 具体值未知,若校验则 302 后新用户直接下载失败,
风险与 123(YunX 只强制 Referer)不对等。宜单独 PR,并需先确认。
## 已确认无需改动
`115`、`115_share`、`115open`、`123_share`、`quark`、`quark_uc_tv`、
`baidu_photo`、`thunder`、`139`、`lanzou`、`uc` 均不在两张代理表内,
默认即 302。
`quark_open` 带的头是 `Cookie`(私有头),`DRIVER_FORCE_PROXY` 对它是
**正确配置**,客户端多线程对其结构性不可行,故不动。
## 未验证
无真实凭据,未实机比对 302 前后结果。**不保证修复任何具体故障。**
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cf411de to
4ed1b4b
Compare
pikachuren
left a comment
There was a problem hiding this comment.
🙏 感谢贡献本 PR!以下是本次代码审查结果。
总体结论:✅ Approve ⭐⭐⭐⭐
当前 head:4ed1b4b480db40e1858e9b9211e9a8cc074e4137
三件事全部做到位:取链返回 UA/Referer、/api/fs/link 打通 headers 透传、123pan/123open 移出默认代理表。作者在 PR 描述和注释中明确说明了「行为移植自 YunX,未实机验证」,透明度很好。
逐模块核查
✅ 115 / 123pan / 123open / quark_uc_tv — 返回 {url, headers} 重构
- 115:
getDownloadUrl追加{ "User-Agent": UA }合理——115 的 downurl 接口本身就是按请求方 UA 签发的,与 115open/115_share 对齐。 - 123pan/123open:
pan123DownloadHeaders()返回Referer: https://yun.123pan.cn/+ UA。Referer 一致(123pan 内部跟随 302 时已用同域 Referer),本次只是让最终直链也带上该头。 - quark_uc_tv:与同族
quark/util.ts的getDownloadUrl对齐,quarkTvDownloadHeaders()内联在文件底部,清晰。 - 123pan
getDownloadLink的 fallback 逻辑:将return downloadUrl改为finalUrl = downloadUrl,逻辑等价,无行为差异。
✅ proxy.ts — 将 123pan/123open 移出 DRIVER_PREFER_PROXY
注释解释了原因:直链只需 Referer + UA,浏览器/下载器可自供,服务端代理反而占用子请求预算并限制多线程分片。逻辑正确。
对现有用户的影响:DRIVER_PREFER_PROXY 只影响新建存储的默认值(web_proxy 字段),已存在的存储配置不会被修改,向后兼容。
✅ server/fs.ts — /api/fs/link 新增 link() 优先路径
- admin-only 门控保持:
if (!isAdmin(user)) return permissionDenied(c)在 PR 变动前后均在(line 1284),正确——headers中可能含 Cookie/Authorization,非管理员不得取得。 link()可选扩展:用(driver as any).linkduck-typing 检查,失败时回退driver.get()+raw_url_headers,再回退代理地址,三层降级合理。raw_url_headers字段:已在internal/driver/base.ts:12定义(raw_url_headers?: Record<string, string>),本 PR 只是补全了驱动侧的赋值,无类型破坏。
✅ fs_link.test.ts — 权限门回归测试
新增两个测试:
- guest 调
/api/fs/link→ 403(直链可能带私有头) - admin 不被门拦下,响应体含
url字段,headers缺省时不凭空出现
覆盖最关键的权限边界,方向正确。
P2 建议(非阻塞,供后续参考)
-
pan123DownloadHeaders()在 123_open/util.ts 与 123pan/util.ts 中完全重复(常量值相同,函数实现相同)。可以考虑提取到src/backend/drivers/123_common/headers.ts复用,消除两处同步维护的风险。当前不影响正确性,不要求本 PR 改动。 -
User-Agent是 Fetch API 的禁止请求头(Forbidden request header):若浏览器端 JS 直接使用/api/fs/link返回的 headers 去fetch(url, { headers }),UA 会被静默忽略。但/api/fs/link是 admin-only 端点,主要受众是配置下载管理器(aria2/NDM/IDM 等)的管理员,这些工具可以设置任意头,影响范围有限。建议在 API 文档(或端点注释)补一句:「headers 中的 User-Agent 仅对支持自定义请求头的下载工具有效,浏览器 fetch 会忽略它」。 -
link()调用约定(行 1337):linkFn.call(driver, reqPath, resolved.physical ?? "/")是未来驱动实现link()时需遵循的签名。目前没有任何驱动实现它,建议在StorageDriver接口中加一条注释说明预期签名link?(reqPath: string, physicalPath: string): Promise<{url: string; headers?: Record<string, string>}>,避免后续实现者各自理解不一致。
依赖与供应链
无新依赖引入,无版本变更,无供应链风险。
🤖 AI 自动审核声明
本评论由 AI 辅助的自动化评审生成,已经过人工主导的逐条复核。
重要提醒:本评论基于静态代码分析和本地测试,未在真实云盘环境中验证实际下载行为(与作者 PR 描述一致)。建议维护者在合并前对四个驱动的直链下载做一次实机验证。如有任何发现与本评论不符,请以维护者判断为准。
|
您好,感谢您的贡献, |
羡慕
|
这是什么
行为移植 + 链路打通,不是故障修复。
为什么不能只靠服务端代理
原先是「Worker 替客户端搬字节」的形态。在 Cloudflare Workers 上这条路有固定代价:
参考 YunX:同一批直链在客户端可开 32~512 线程(迅雷锁 8)。
要吃到这个能力,就必须把直链连带 UA/Referer 交给客户端。
改动一:四个驱动的取链函数返回请求头
Promise<string>→Promise<{ url, headers }>,驱动赋给raw_url_headers。User-Agent115open同一约定(UA 绑进取链请求,注释:「115 防盗链校验通过率高」)Referer+User-Agentquark已返回{url, headers}Referer+User-AgentPan123Api对 CDN 直链注明需Referer: https://yun.123pan.cn/Referer+User-Agent改动二:
123pan/123open移出DRIVER_PREFER_PROXY这张表决定新建存储时
web_proxy的默认值:命中即默认勾选,也就是默认由Worker 代理字节 —— 客户端拿不到直链,多线程无从发生。
移出后默认改为 302 直链。依据是仓库自己的判定:
server/proxy_request.ts的PRIVATE_HEADER_NAMES只有authorization/cookie,其注释明确写着 UA / Referer / Origin「浏览器可以自己提供」,不构成必须服务端代理的理由。
只影响新建存储的默认值:已有存储有显式持久化的
web_proxy字段,effectiveWebProxy优先读显式值,行为不变;管理员随时可以再勾回来。改动三:
/api/fs/link接通link()并返回 headers排查时发现
link()是死代码:10 个驱动实现了它(
115_share、123_share、139、189pc、aliyundrive_share、dropbox、mega、onedrive_sharelink、pikpak_share、wps),但下载链路里没有任何地方调用。而
fs.ts的/link端点只返回{url},既不调link()也不回headers。后果:多线程下载器没有任何途径拿到驱动指定的精确头 —— 302 只能交给浏览器
自带的 UA/Referer,取不到驱动指定的值。这是「无法让客户端多线程」的根因之一。
改造
/api/fs/link:link(),成功则直接返回{url, headers};link()不可用或失败时回退driver.get()的raw_url+raw_url_headers;linkOk时跳过driver.get(),省一次上游往返;headers为空时不出现该字段,保持向后兼容。安全性:
link()返回的头可能含Cookie/Authorization。该端点本就是admin-only(上方
isAdmin判定),受众正是「正在配置下载管理器的管理员」,原样返回是恰当的。已加
fs_link.test.ts守住权限门,防止回归成任意用户可取。为什么
baidu_netdisk没一起改三条
download_api路径都只带 UA,其中official要求恰为pan.baidu.com。百度是否校验 UA 具体值未知,若校验则 302 后新用户直接下载失败,
风险与 123(YunX 只强制 Referer)不对等。宜单独 PR,并需先确认。
已确认无需改动
115、115_share、115open、123_share、quark、quark_uc_tv、baidu_photo、thunder、139、lanzou、uc均不在两张代理表内,默认即 302。quark_open带的头是Cookie(私有头),DRIVER_FORCE_PROXY对它是正确配置,客户端多线程对其结构性不可行,故不动。
影响面
getDownloadUrl/getDownloadLink返回类型由字符串变为对象(签名变更),四个驱动内全部调用点已同步;这四个 util 没有被其它驱动引用。
internal/driver/proxy.ts两张表的成员变化,proxy.test.ts已同步。fs.ts的/link响应新增可选headers字段,缺省时不出现。未验证
无真实凭据,未实机比对结果。不保证修复任何你遇到的问题。