Files
WeChatHookBot/docs/原始CDN下载实现指南_给第三方框架.md

153 lines
4.6 KiB
Markdown
Raw Permalink 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.
# 原始 CDN 下载实现指南(给第三方框架)
这份文档只讲“原始 Hook 协议怎么下图”,不依赖本项目的 `WechatHookClient``ImageProcessor` 封装。
## 1) 接口结论(按本仓库实际代码验证)
- 接口:`POST /api/cdn_download`
- 请求体字段:
- `fileid`CDN 文件标识
- `asekey`AES 密钥(注意字段名是 `asekey`,不是 `aeskey`
- `imgType``1` 原图,`2` 缩略图
- `out`本地保存路径Hook 所在机器可写路径)
- 成功判定:响应 JSON 中 `errCode == 1`
已在代码中看到的依据:
- `WechatHookBot/WechatHook/http_client.py:752`
- `WechatHookBot/WechatHook/http_client.py:775`
- `WechatHookBot/WechatHook/http_client.py:793`
- `WechatHookBot/WechatHook/http_client.py:801`
---
## 2) 参数从哪里来(消息 XML
图片消息里一般在 `<img ... />` 标签:
- 原图 fileid 候选:`cdnbigimgurl` / `cdnmidimgurl` / `cdnhdimgurl` / `fileid`
- 原图 key`aeskey`
- 缩略图 fileid`cdnthumburl`
- 缩略图 key`cdnthumbaeskey`(若没有可回退 `aeskey`
本仓库提取逻辑:
- `WechatHookBot/WechatHook/client.py:1386`
- `WechatHookBot/WechatHook/client.py:1393`
---
## 3) 你朋友可直接照抄的实现流程
1. 解析微信消息 XML拿到
- 原图:`fileid = cdnbigimgurl(或候选)``aeskey`
- 缩略图:`thumb_fileid = cdnthumburl``thumb_key = cdnthumbaeskey or aeskey`
2. 先调用一次原图:`imgType=1`
3. 如果失败,再调用缩略图:`imgType=2`
4. 成功后检查 `out` 文件存在且大小 `> 0`
推荐这么做的原因:有些消息原图拉不到,但缩略图能拉到。
---
## 4) 最小请求示例curl
```bash
curl -X POST "http://127.0.0.1:8888/api/cdn_download" \
-H "Content-Type: application/json" \
-d '{
"fileid": "<cdnbigimgurl>",
"asekey": "<aeskey>",
"imgType": 1,
"out": "D:/temp/wx_img_001.jpg"
}'
```
---
## 5) Python 最小实现(可直接给朋友)
```python
import os
import requests
import xml.etree.ElementTree as ET
def parse_img_xml(xml_text: str):
root = ET.fromstring(xml_text)
img = root.find(".//img")
if img is None:
raise ValueError("xml里没有<img>标签")
fileid = (
img.get("cdnbigimgurl", "")
or img.get("cdnmidimgurl", "")
or img.get("cdnhdimgurl", "")
or img.get("fileid", "")
)
aeskey = img.get("aeskey", "")
thumb_fileid = img.get("cdnthumburl", "")
thumb_key = img.get("cdnthumbaeskey", "") or aeskey
return fileid, aeskey, thumb_fileid, thumb_key
def cdn_download(base_url: str, fileid: str, aeskey: str, out_path: str, img_type: int = 1, timeout: int = 60):
payload = {
"fileid": fileid,
"asekey": aeskey, # 注意这里是 asekey
"imgType": img_type,
"out": out_path,
}
resp = requests.post(f"{base_url}/api/cdn_download", json=payload, timeout=timeout)
resp.raise_for_status()
data = resp.json()
ok = isinstance(data, dict) and data.get("errCode") == 1
if not ok:
return False, data
if not os.path.exists(out_path) or os.path.getsize(out_path) <= 0:
return False, {"error": "hook返回成功但文件未落盘", "resp": data}
return True, data
def download_image_with_fallback(base_url: str, xml_text: str, out_path: str):
fileid, aeskey, thumb_fileid, thumb_key = parse_img_xml(xml_text)
if fileid and aeskey:
ok, data = cdn_download(base_url, fileid, aeskey, out_path, img_type=1)
if ok:
return out_path
if thumb_fileid and thumb_key:
ok, data = cdn_download(base_url, thumb_fileid, thumb_key, out_path, img_type=2)
if ok:
return out_path
raise RuntimeError("原图/缩略图都下载失败")
```
---
## 6) 常见坑(你教朋友时重点强调)
- `asekey` 字段名拼错:写成 `aeskey` 会直接失败。
- `fileid` 取错:优先 `cdnbigimgurl`,不要只盯一个字段。
- 只试原图不试缩略图:很多“偶发失败”是这么来的。
- 路径不可写:`out` 必须是 Hook 进程有权限写入的本机路径。
- 仅看 HTTP 200必须再看 `errCode` 和文件是否真正写出来。
---
## 7) 与 `download_img` 的区别(避免混淆)
- `/api/cdn_download`:走 `fileid + asekey` 这条 CDN 参数下载链路(你现在要的)。
- `/api/download_img`:走 `MsgId/to_user/from_user/total_len...` 这条“按消息参数”下载链路。
`/api/download_img` 的官方文档在:
- `新接口/下载图片.md:1`
如果你朋友框架已经能拿到 `<img>` 里的 `cdnbigimgurl/aeskey`,优先实现 `/api/cdn_download` 即可。