最近给 Qx 社区插件整理市场截图时,需要把几十张图片迁移到访问更快的 CDN。本文记录 aapi.helioho.st/upload.php 的实际请求格式、返回结构、限流规则,以及一个可以断点续传的批量上传脚本。

接口信息
| 项目 | 内容 |
|---|---|
| 上传地址 | https://aapi.helioho.st/upload.php |
| 请求方法 | POST |
| 请求格式 | multipart/form-data |
| 文件字段 | image |
| 成功图片域名 | https://img.meituan.net/content/ |
| 单张限制 | 最大 20 MB |
| 页面单次选择 | 最多 10 张 |
网页上传入口是:
1 | https://695402.xyz/mt/?ref=www.549.tv |
用 curl 上传一张图片
接口会检查来源。只发送文件通常会返回 HTTP 403,需要带上网页使用的 Origin、Referer 和常见浏览器标识:
1 | curl -fsS 'https://aapi.helioho.st/upload.php' \ |
成功时返回 JSON:
1 | { |
业务代码不要只检查 HTTP 状态,还要同时检查 code === 200 和 data.url。接口触发限流时仍可能返回一段合法 JSON,但其中 code 是 500,data 也可能从对象变成空数组。
可断点续传的批量脚本
下面的 Python 脚本读取 uploads.json。键是本地图片路径,值为空表示待上传;每成功一张就立即写回 CDN 地址,因此中途失败后可以直接重新运行。
先准备清单:
1 | { |
保存以下代码为 upload_images.py:
1 | import json |
运行:
1 | python3 upload_images.py |
限流规则
这次实际迁移 32 张截图时遇到了两层频率限制:
- 1 分钟最多上传 10 张。
- 1 小时最多上传 30 张。
服务端对应的错误信息分别包含“1分钟内限制10张”和“1小时内限制30张”。批量任务应当控制速度、持久化进度,并在收到限流响应时停止或延迟重试,不能把每个失败立即连续重放。
如果终端配置了共享代理,代理出口可能和其他请求共用额度。排查时可以比较代理与直连结果;不要为了绕过限制进行高并发上传。
接入静态站点
我的处理方式是保留本地源图,同时维护一份文件名到 CDN URL 的映射:
1 | { |
构建页面时优先使用经过校验的 CDN URL,映射缺失时退回本地文件:
1 | const cdnUrl = screenshotCdn?.[pluginId]?.[filename]; |
这样页面能利用 CDN,插件包或离线环境仍有本地图片可用。新增图片也不会因为忘记上传而直接显示空白。
上传后的检查
界面截图、图标和其他包含细小文字或锐利边缘的图片,建议先转为 PNG:
1 | sips -s format png ./screenshot.jpg --out ./screenshot.png |
实测 JPEG 上传后会再次有损压缩。Qxpicture 的一张界面截图从本地 118,800 字节变成 88,395 字节,文字边缘明显变软;同一源图转成 PNG 后再上传,CDN 文件解码后的像素与上传文件完全一致。
至少检查以下内容:
- 每个 URL 都能返回 HTTP 200。
Content-Type是图片类型。- 远端像素宽高与本地源图一致。
- 页面中实际加载的是 CDN URL,而不是旧缓存或本地路径。
- 截图中没有令牌、账号、主机名等敏感信息。
本次最终迁移了 21 个插件图标和 32 张插件截图。53 个 CDN 文件均返回 image/png,解码后 53/53 与上传文件逐像素一致。PNG 文件的字节哈希仍可能因元数据或压缩方式不同而变化,因此应比较解码像素,而不是只比较文件哈希。
使用边界
这是第三方公开接口,域名、限流和返回格式都可能调整。生产使用时应保留本地源文件、记录返回 URL,并让构建过程具备回退路径。不要把包含访问令牌、私人页面或未遮盖账号信息的截图上传到公共图床。
实测日期:2026-09-09