Files
Skill-123yunpan/references/competitor-upload-patterns.md
T
nxxy335 f0ecfa6de0 chore: 初始化 123yunpan skill 仓库 (v1.3.0)
- 完整 skill 本体:SKILL.md / README.md / manifest.json / config.json
- scripts/123yunpan.py:零依赖 CLI(含空间双配额、QPS 限流、零依赖 XLSX)
- references/ 参考资料
- 排除 .workbuddy/ 开发目录与 __pycache__
2026-09-27 22:41:43 +08:00

125 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 123云盘上传模式 & 竞品分析
> 来源:分析 Skillhub 上 `123pan-upload` skill 的实现,提取可借鉴的模式。
## 短直链生成(Short Direct Link)
直链 URL 包含 user_id 和文件路径,较长且暴露用户信息。短直链只用 file_id,更隐私友好:
```python
import base64, json
def get_user_id_from_token(token: str) -> int:
"""从 JWT token 解析 user_id,无需额外 API 调用"""
parts = token.split(".")
if len(parts) >= 2:
payload = parts[1]
padding = 4 - len(payload) % 4
if padding != 4:
payload += "=" * padding
data = json.loads(base64.b64decode(payload))
return data.get("id", 0)
return 0
def get_short_direct_link(user_id: int, file_id: int) -> str:
return f"https://{user_id}.v.123pan.cn/{user_id}/{file_id}"
```
**对比:**
| 类型 | URL 格式 | 隐私性 | 可直链下载 |
|------|---------|--------|-----------|
| 分享链接 | `https://www.123pan.com/s/{shareKey}` | ✅ 好 | ❌ 需跳转 |
| 完整直链 | `https://{user_id}.v.123pan.cn/{user_id}/{file_id}/{filename}` | ⚠️ 暴露路径 | ✅ |
| 短直链 | `https://{user_id}.v.123pan.cn/{user_id}/{file_id}` | ⚠️ 暴露 user_id | ✅ |
## 上传流程(V2 API)
> ⚠️ **2026-05 验证**:以下流程经过实际 API 调用验证,修正了早期文档中的错误。
### 两个域名
| 域名 | 用途 | 端点 |
|------|------|------|
| `https://open-api.123pan.com` | 主 API(认证、文件管理、chunked create) | `/api/v1/*`, `/api/v2/*`, `/upload/v2/file/create` |
| `https://openapi-upload.123242.com` | 上传专用(获取上传域名返回此值) | `/upload/v2/file/single/create`, `/upload/v2/file/slice`, `/upload/v2/file/upload_complete` |
获取上传域名:`GET /upload/v2/file/domain` → 返回 `["https://openapi-upload.123242.com"]`(列表,非对象)
### 单文件上传(<100MB)
```
1. GET open-api.123pan.com/upload/v2/file/domain → 获取上传服务器地址
2. POST openapi-upload.123242.com/upload/v2/file/single/create → multipart/form-data 上传
```
**关键坑点**:
- `single/create` **必须用 multipart/form-data**,不能用 JSON body。JSON 会导致 500 服务器崩溃。
- 表单字段:`parentFileID`(text), `filename`(text), `etag`(text), `size`(text), `file`(file)
- `duplicate` 字段:**不要传 `0`**(会导致 "duplicate参数错误")。不传默认覆盖,或传 `1`(重命名)/`2`(覆盖)。
- 响应:`{"code":0, "data":{"fileID": 12345, "completed": true}}` — 无需额外上传步骤。
### 分片上传(100MB-10GB)
```
1. POST open-api.123pan.com/upload/v2/file/create → 创建上传任务(主域名)
2. POST openapi-upload.123242.com/upload/v2/file/slice → 逐片上传(上传域名)
3. POST openapi-upload.123242.com/upload/v2/file/upload_complete → 完成上传(上传域名)
```
**关键坑点**:
- `create` 调用主 API 域名,不是上传域名!
- `slice` 和 `upload_complete` 调用上传域名。
- `slice` 请求体字段名为 `partMd5`(注意:不是 `sliceMD5`,后者会导致 500)。
- 分片大小由 `create` 响应中的 `sliceSize` 决定(通常 16MB)。
### SHA1 秒传
```python
# create_file 响应中 reuse=true 表示文件已存在,跳过上传
if create_result["reuse"]:
return {"file_id": create_result["file_id"], ...}
```
### 上传校验轮询
```python
# upload_complete 响应中 completed=false 时需轮询
# 建议间隔:1 秒
# 最大等待:~5 分钟/GB(10GB 文件约 50 分钟)
# 文件大小越大,校验时间越长
for attempt in range(max_retries):
resp = api_post("/upload/v2/file/upload_complete", {"preuploadID": preupload_id})
if resp["data"].get("completed"):
return resp["data"] # 校验完成
time.sleep(1) # 按 API 文档要求,每秒轮询一次
```
### MD5 作为 Etag
上传创建时需要提供文件的 MD5 作为 `etag` 字段:
```python
import hashlib
etag = hashlib.md5(open(file_path, "rb").read()).hexdigest()
```
## WebDAV 上传(>10GB 文件)
API 上传上限 10GB,超大文件可用 WebDAV + rclone:
```bash
# 1. 配置 rclone(隔离配置,避免读取其他云服务凭证)
rclone config --config ~/123pan-rclone.conf
# 添加 "123pan-webdav" remote
# 2. 上传
RCLONE_CONFIG=~/123pan-rclone.conf rclone copy /path/to/large/file 123pan-webdav:/folder -P
# 3. 上传后通过 API 查找文件(WebDAV 上传有 30-90 秒索引延迟)
# 需要轮询 file/list 接口等待文件出现
```
**注意:** WebDAV 上传后文件不会立即出现在 API 列表中,需要重试查找(最多 30 次,每次间隔 3 秒)。
## 安全实践
- rclone 配置隔离:用 `RCLONE_CONFIG` 环境变量指定独立配置文件
- 凭证存储:用环境变量或 `.env` 文件,不要硬编码
- Token 刷新:123yunpan.py CLI 已自动处理 401 响应时的 token 刷新