API 图库插件开发日志
项目:halo-plugin-api-gallery(API 图库) 状态:v1.4.2 已发布,开源地址 https://github.com/lu7875/halo-plugin-api-gallery 插件包:https://github.com/lu7875/halo-plugin-api-gallery/releases/download/v1.4.2/api-gallery-1.4.2.jar
一、为什么做这个插件
站点想有一个图库页,但直接自己存图有几个绕不开的问题:服务器存储有限、图片版权归属复杂、第三方图床又有防盗链和失效风险。
最后定的思路是做一个聚合器而不是存储器:后台配置任意图片 API 地址,插件定时拉取素材,但只缓存地址等元数据,文件始终由第三方图源提供——不下载、不写入附件库、不占本地存储。图挂了最多是前台加载不出,站点本体不受影响。

二、架构设计
整个插件围绕一条数据流展开:
后台设置表单 → ConfigMap(api-gallery-config)
│ watch(保存即触发)
▼
GalleryService.sync()
│ ApiUrlSafety 校验 + 3xx 逐跳复检
│ HTTP GET 各数据源(Redirect.NEVER)
▼
内存缓存(图片元数据,进程内)
│
┌───────────┴───────────┐
▼ ▼
公开只读组 /items /random PhotoBridgeService → Photo 记录(只写地址)
几个关键设计决策:
- 结构自适应解析:图片 API 的响应结构五花八门,插件自动识别顶层数组、
{items:[...]}包裹、单对象(随机图)三种结构,字段名(url/id/title/tags)可单独指定,留空自动推断。 - 对接官方图库管理插件:把图片地址写成
Photo记录,后台/console/photos和主题/photos页面直接展示,依然不占存储。 - 访客自动放行:插件启动时自动创建
api-gallery-viewer角色并打聚合标签合并进匿名角色,前台页面无需登录。

三、开发过程中的关键问题
1. 随机图源没有列表接口怎么办(v1.1.0)
很多免费图源每次请求直接 302 跳转到一张随机图,没有列表接口。解决办法是重复采样 + 去重:按配置的采样次数串行请求(120ms 间隔,不打挂图源),收集每次的跳转地址去重后攒成图集。实测采样 12 次约 3.4 秒能拿到 11–12 张不重复的图。
2. 攒满后图库永久静止(v1.3.0 修)
这是最隐蔽的一个 bug:旧版本同步时把旧缓存排在前面、新采样的图排在后面,达到「最多累积」上限后被截断丢弃的永远是新图。结果就是图池一旦攒满,定时同步照常跑,内容却永久静止。
修复方案是滚动更新:新图插最前、最老的被淘汰(并同步从图库删除对应记录),图池大小稳定但内容每轮都在换。同时保证拉图失败时保住已有数据,不会清空。
3. 安全整改(v1.4.0)
复查时发现两个必须堵上的口子:
- 匿名可读管理接口:1.3.1 及以前所有接口共用一个 API group,匿名角色拿到该组的 get/list,意味着访客可以匿名读取图源地址明细、甚至通过
/diagnose让服务端对外发请求。1.4.0 拆成两个 group,管理诊断组永不对匿名放行。 - SSRF 风险:插件会根据后台配置的地址发请求,如果不加校验,内网地址、云厂商元数据端点(169.254.169.254)都可能被指向。现在每次请求前统一校验协议与网段,DNS 解析后的每一条 A/AAAA 记录都过检查,防 DNS rebinding。
4. 应用市场审核整改(v1.4.1 / v1.4.2)
提交 Halo 应用市场后收到三条审核意见:3xx 跳转可绕过 SSRF 防护、上架链接 404/500、需补充人工测试声明。
- v1.4.1:所有对外请求改为
Redirect.NEVER,新增sendFollowingRedirects()手动逐跳跟随,每一跳跳转前重新校验协议、主机与 DNS 解析 IP,最大 5 跳防重定向循环;链接统一到 GitHub 仓库;补齐 AI 辅助编码与人工复查声明。 - v1.4.2:复查时发现 302 随机图源把
Location直接当作图片地址写入缓存与图库。服务端虽不跟随该跳转(不构成直接 SSRF),但内网、回环、云元数据或非 http 协议的地址仍会污染业务数据并展示到前台。新增safeImageUrl(),对Location、200 兜底文本、随机单张 JSON 的url统一归一为绝对 URL 后再执行完整校验,不合法直接丢弃;同时让/diagnose的脱敏实现与上架材料声明完全一致(去掉firstRow字段值与异常message,补contentType),并补建 GitHub Release 提供可下载插件包。
四、质量保障
53 个单元测试覆盖了响应解析、端到端拉取(起本地 HTTP 服务模拟图源)、SSRF 校验边界(含 172.32 放行反例)、302/307 跳转逐跳复检与循环保护、响应中图片地址的二次校验、图库写入与撤回隔离。其中端到端测试全程只产生内存对象,不落任何本地文件。
五、后续计划
- 完成 Halo 应用市场上架审核,插件包与更新日志持续同步到 GitHub Releases
- 支持更多响应结构(如分页自动抓取)
- 图源健康度统计与自动降级
- 展示页主题跟随站点暗色模式
评论