Repository navigation
fix(115): 修复 115 驱动(旧驱动失效 + 子目录路径解析失败), fixes #128 - #152
Merged
Merged
Conversation
added 2 commits
October 25, 2026 09:57
## 问题
后台添加 115Open 驱动后,存储状态恒为 [115] API error (),浏览任何目录都失败。
## 根因
仓库里存在两套 115 驱动实现:
- src/backend/drivers/115/(类 Client115)—— 已损坏
- src/backend/drivers/115open/(类 Pan115Driver)—— 正确,自 Go 版移植
storage.ts 的驱动工厂按 normDriver(toLowerCase().replace(/[^a-z0-9]/g,""))
做 if-else 链式匹配。DB 里的 115Open 归一化为 115open,被靠前的旧驱动分支
截走;下方正确的 Pan115Driver 分支因列出同样的 115open 而永远走不到,
成为死代码。
旧驱动 Client115 有三处错误,叠加导致报错信息为空:
1. URL 路径重复:util.ts:10 的 API_BASE 已含 /open,util.ts:100 又请求
"/open/ufile/files",实际请求 /open/open/ufile/files。实测返回
{"state":false,"message":"Method POST does not exist","code":0},
且响应里没有 error / errno / errcode 字段。
2. HTTP 方法错误:util.ts:38-70 的 request() 用 POST + JSON body,
而 115 开放平台要求 GET + query string。
3. 错误码字段名错误:util.ts:65-67 的错误模板取
data.error || data.errmsg || data.errno || data.errcode,
上述字段一个都不存在,于是输出 [115] API error () —— 括号里空空如也,
与用户看到的 status 一字不差。
## 改动
1. 删除 src/backend/drivers/115/(driver.ts / types.ts / util.ts,共 489 行)。
grep 确认无其他引用。
2. storage.ts:删掉 Driver115 的 import 与整个旧分支,留注释说明
115 / 115Open 统一走 Pan115Driver。normDriver.startsWith("115")
分支已能覆盖 115 / 115Open / 115cloud / 115netdisk 等所有变体。
## 验证
- npm run lint(tsc --noEmit)通过。
- 测试全过:drivers 189、server 206、model 39、regress 71、cache 24、
pkg 50、189 20、store 13,合计 626 pass / 0 fail。
- 用真实 115 token 对 Pan115Driver 做全链路验证:init、list、get、
mkdir、rename、delFile、refreshToken 均成功。
- 线上部署后存储 status 由 [115] API error () 变为 work,/115 可正常浏览。
原配置里的 access_token / refresh_token 已过期(40140126 / 40140120),
换新 token 后 status 恢复 work。该问题与本次代码修复相互独立。
## 问题
115 存储挂载后根目录可浏览,但进入任意子目录(或访问子目录下的文件、
新建/重命名/移动)时报:
115 网盘 API 错误(code 20001 目录名称不能为空。)
## 根因
两个缺陷叠加,导致一次性路径解析失败且兜底逻辑被跳过:
1. resolveFolderId 拼接的 fullPath 多出一个斜杠(driver.ts:184):
const fullPath = `/${rootId === "0" ? "" : rootId}${clean === "/" ? "" : clean}`
root_id 默认 "0",于是 `/` + `` + `/测试` = `//测试`。
115 开放平台对 folder/get_info 的 path 参数严格校验:
| path | 返回 |
| --- | --- |
| `/测试` | state:true,返回 file_id |
| `//测试` | code 20001 目录名称不能为空。 |
| `测试`(缺前导斜杠) | code 990002 参数错误。 |
2. request() 的业务错误是裸 Error,不带 code(util.ts:231),
只有 430004 分支才设置 err.code。resolveFolderId 的回退判断
`if (e?.code !== ERR_OBJECT_NOT_FOUND && e?.code !== 990002) throw e`
因 e.code === undefined 而直接 rethrow,逐层解析兜底永远走不到
—— 而逐层解析(用 ufile/files 列父目录)本身是通的。
根目录恰好能浏览,是因为 clean === "/" 时提前 return 了。
## 改动
1. driver.ts:root_id 非 "0" 时才拼前缀,避免产生 "//xxx":
const rootPrefix = rootId === "0" ? "" : `/${rootId}`
const fullPath = `${rootPrefix}${clean}`
2. driver.ts:回退条件增加 20001(空目录名),覆盖更多 path 相关失败。
3. util.ts:所有业务错误(含 token 刷新后重试仍失败)统一把 code
挂到 Error 对象上,调用方才能按 code 决定是否回退。
## 验证
- 本地用真实 115 token 跑通 list("/")、list("/测试")、get(apk)
(5874314 字节,成功取得下载链接)。
- npm run lint 通过。
- 测试全过:drivers 189、server 206、regress 71、189 20、
model 39、cache 24、pkg 50、store 13,合计 612 pass / 0 fail。
- 线上部署后:
- POST /api/fs/list {"path":"/115/测试"} → code 200,返回 apk
- POST /api/fs/get {"path":"/115/测试/...apk"} → code 200,raw_url 正常
Suyunmeng
approved these changes
Oct 25, 2026
pikachuren
reviewed
Oct 25, 2026
pikachuren
left a comment
Collaborator
There was a problem hiding this comment.
方向没问题,Bug 1 / Bug 2 的定位和修法都对,// 消失、code 挂到 Error 上这两处我本地按边界值推演过,符合预期。
两点建议:
startsWith("115")(586 行)在115Share分支(1051 行)之前,115Share归一化成115share会先命中,被Pan115Driver构造(它没有 access_token)。这是 main 上就有的老问题,但本 PR 把startsWith("115")定位成「115 统一入口」,建议顺带排除 share,或把 share 分支挪到前面。root_id非默认时/{rootId}不是 Go 的语义(Go 用parentPath拼接,parentPath你在init()里算了却没用)。现在会多发一次注定失败的folder/get_info,在 CF 45 次 subrequest 预算下不划算;而且parentPath没解析出来时不要退化传clean,否则可能解析到账号根目录的同名目录。
另外这个修复挺适合补一个纯函数单测(默认 root / 非默认 root / 尾斜杠 / 空路径),仓库里 drivers/189/util.test.ts 就是现成模板。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #128
问题
Issue #128 反馈:添加
115open存储后提示[115] API error (),无法使用。该问题由两个 bug 引起。
Bug 1:
115Open被失效的旧驱动接管,恒报[115] API error ()仓库里存在两套 115 驱动:
src/backend/drivers/115/Client115src/backend/drivers/115open/Pan115Driversrc/backend/internal/op/storage.ts的驱动工厂按normDriver(
toLowerCase().replace(/[^a-z0-9]/g, ""))做 if-else 链式匹配。DB 里的
115Open归一化为115open,被靠前的旧驱动分支截走:而下方正确的
Pan115Driver分支(含 token 刷新持久化回调)因列出同样的
115open而永远走不到,成为死代码。旧驱动
Client115有三处错误,叠加导致报错信息为空:util.ts:10的API_BASE已含/open,util.ts:100又请求
"/open/ufile/files",实际请求/open/open/ufile/files。实测返回
{"state":false,"message":"Method POST does not exist","code":0},响应里没有
error/errno/errcode字段。util.ts:38-70用POST+ JSON body,115 开放平台要求 GET + query string。
util.ts:65-67的错误模板取data.error || data.errmsg || data.errno || data.errcode,一个都不存在,于是输出
[115] API error ()—— 括号里空空如也。Bug 2:子目录解析失败,报
code 20001 目录名称不能为空。Bug 1 修好后,根目录可浏览,但进入任意子目录(或访问子目录下的文件、
新建/重命名/移动)仍失败。两个缺陷叠加,导致一次性路径解析失败
且兜底逻辑被跳过:
resolveFolderId拼接的fullPath多出一个斜杠(driver.ts:184):root_id默认"0",于是/+ `` +/测试= `//测试`。115 开放平台对 `folder/get_info` 的 `path` 严格校验:
/测试state:true,返回file_id//测试code 20001 目录名称不能为空。测试(缺前导斜杠)code 990002 参数错误。request()的业务错误是裸Error,不带code(util.ts:231),只有
430004分支才设置err.code。resolveFolderId的回退判断if (e?.code !== ERR_OBJECT_NOT_FOUND && e?.code !== 990002) throw e因
e.code === undefined而直接 rethrow,逐层解析兜底永远走不到—— 而逐层解析(用
ufile/files列父目录)本身是通的。根目录恰好能浏览,是因为
clean === "/"时提前 return 了。改动
src/backend/drivers/115/(driver.ts/types.ts/util.ts,共 489 行)。
grep确认无其他引用。src/backend/internal/op/storage.ts:删掉Driver115的 import 与整个旧分支,留注释说明 115 / 115Open 统一走
Pan115Driver。normDriver.startsWith("115")分支已能覆盖115/115Open/115cloud/115netdisk等所有变体。src/backend/drivers/115open/driver.ts:root_id非"0"时才拼前缀,避免产生
//xxx;回退条件增加20001。src/backend/drivers/115open/util.ts:所有业务错误(含 token 刷新后重试仍失败)统一把
code挂到Error对象上,调用方才能按 code决定是否回退。
验证
npm run lint(tsc -p tsconfig.json --noEmit)通过。cache 24、pkg 50、store 13,合计 612 pass / 0 fail。
Pan115Driver做全链路验证:init()(userInfo)→user_id 103645653list("/")→测试/;list("/测试")→ apkget("/测试/xxx.apk")→ 5874314 字节,成功取得下载链接mkdir→updateFile(rename) →delFile→ 三步均成功并清理refreshToken()→ 成功,刷新后 userInfo 仍返回同一user_id[115] API error ()变为workPOST /api/fs/list {"path":"/115/测试"}→ code 200,返回 apkPOST /api/fs/get {"path":"/115/测试/...apk"}→ code 200,raw_url正常