随机图片 API
为 Halo 2.x 提供随机图片接口:管理员配置若干条规则(API 路径 + 存储策略 + 附件分组),访问该路径时从对应附件中随机选一张图片,并以 302 跳转到附件地址。
适合博客随机头图、每日一图、相册随机展示等场景。
功能
- 支持多条规则,每条规则独立配置路径、存储策略(可选)和附件分组,并可单独启用/停用。
- API 路径可在 Halo 控制台修改,保存后立即生效,无需重启插件。
- 分组留空表示该存储策略下的全部可见分组(自动排除头像等隐藏分组)。
- 只筛选图片附件:优先使用
image/*媒体类型;媒体类型缺失时按扩展名判断。 - 排除 SVG、XML、HTML 等可能带来同源脚本风险的附件。
- 跳转响应使用
302 Found,并设置no-store等禁止缓存头,避免该 302 响应被浏览器或 CDN 缓存;目标图片的缓存行为由图片自身的响应头和 CDN 配置决定。 - 支持本地存储、S3、OSS 等所有 Halo 存储策略,直接使用附件的公开 permalink,不生成会过期的签名链接。
- 附件名单在内存中短时缓存,并合并并发请求,避免每次访问都扫描附件表。
兼容性
| 项目 | 要求 |
|---|---|
| Halo | >= 2.27.0(已在 Halo 2.27.x 验证) |
| Java | 21 |
安装
从应用市场安装
在 Halo 控制台进入「应用市场」,搜索「随机图片 API」,点击安装并启用。
手动安装
- 从 Releases 下载最新版本的
random-image-api-x.y.z.jar。 - 在 Halo 控制台进入「插件 → 安装 → 本地上传」,选择该 JAR。
- 安装完成后启用插件。
快速开始
- 进入「插件 → 随机图片 API → 随机图片 API」标签页。
- 点击「添加规则」,填写 API 路径,例如
/random/image。 - 按需选择存储策略和附件分组;留空表示不限制。
- 保存后在页面中引用:
<img src="https://your-halo-site/random/image" alt="随机图片" />
验证效果:
curl -I https://your-halo-site/random/image
# HTTP/1.1 302 Found
# Location: /upload/example.jpg
# Cache-Control: no-store, no-cache, must-revalidate, max-age=0
路由提示:推荐使用两段路径(如
/random/image),降低与主题页面、文章永久链接或其他插件路由冲突的概率。/api、/apis、/console、/upload、/archives、/tags等保留前缀会被拒绝。设置页会即时校验路径格式和保留前缀,校验不通过时无法保存。
设置项
在 Halo 控制台进入「插件 → 随机图片 API → 随机图片 API」标签页:
| 设置项 | 说明 |
|---|---|
| 随机图片规则 | 可添加多条规则,每条规则对应一个 API 路径。 |
| 启用该规则 | 关闭后该路径立即停止提供随机图片,规则配置会保留。 |
| API 路径 | 以 / 开头,例如 /random/image。保存后立即生效。 |
| 存储策略 | 可选。留空表示不限制存储策略;选择后仅从该策略取图。 |
| 附件分组 | 可选。留空表示所选策略下全部可见分组(不含隐藏分组);策略与分组同时留空时从全部可见附件中取图。 |
| 附件列表缓存(秒) | 默认 30,范围 0–3600。0 表示每次请求都重新查询;新上传的图片最多延迟一个缓存周期生效。 |
使用示例
随机博客头图(每次刷新换一张):
<img src="/random/image" alt="随机头图" />
在主题模板中作为背景图:
<div style="background-image: url('/random/image')"></div>
no-store等缓存头只作用于 API 返回的 302 响应,不会传递到目标图片。目标图片是否被浏览器或 CDN 缓存,取决于附件存储服务返回的响应头和 CDN 配置;如需固定图片,请直接使用附件永久链接。
升级
- 应用市场安装的插件:在「应用市场 → 已安装」中点击升级。
- 手动安装的插件:下载新版本 JAR,在「插件 → 随机图片 API → 升级」中上传并确认。
- 升级不会修改附件;插件设置会保留,升级后无需重新配置。
- 若版本说明中提示不兼容变更,请先阅读版本说明再升级。
卸载
- 在 Halo 控制台进入「插件」,点击「随机图片 API」的「卸载」。
- 卸载后插件注册的随机图片路径立即失效,配置的规则不再生效。
- 卸载不会删除任何附件,也不会修改文章、页面或主题内容。
- 如需保留当前规则配置,请在卸载前记录设置页内容。
故障排查
访问路径返回 404
- 确认规则已启用,且路径与请求地址完全一致(Halo 路由区分大小写)。
- 路径可能与主题页面、文章永久链接冲突;主题路由优先时请更换路径,推荐两段路径。
- 单段路径(如
/random)更容易冲突,建议改为/random/image。
访问路径返回 503(Image is temporarily unavailable)
- 附件存在但无法生成公开访问地址。检查存储策略是否配置了可访问的域名。
- 若使用 S3 兼容存储,确认存储桶允许公开访问,且策略中填写了正确的访问域名。
跳转后图片返回 403
- 302 的目标地址是否可匿名访问取决于存储策略。请将存储桶或访问域名设置为公开读取。
- 插件不会生成预签名链接,因此私有存储桶无法直接返回图片。
新上传的图片没有立即出现
- 附件名单有缓存,最长延迟一个缓存周期。将「附件列表缓存」设为
0可立即生效,但会增加查询开销。
某些图片始终不出现
- 隐藏分组(如用户头像)中的附件会被刻意排除。
- 如果规则指定了存储策略或附件分组,只会从该范围内取图。
路径无法保存
- 路径必须符合
/a/b形式,不能包含空格、..、//、?、#。 /api、/console、/tags等系统或主题保留前缀会被拒绝。
隐私与数据
- 插件不收集、不上传、不共享任何用户数据或站点数据。
- 插件不发起任何外部网络请求,不包含遥测、统计或崩溃上报。
- 插件仅从 Halo 附件库读取图片名称与公开访问地址,不会读取附件内容。
- 随机图片接口为公开只读接口(设计如此,便于主题直接引用),仅返回 302 跳转,不返回附件元数据。
- 服务器日志只记录规则路径、存储策略名和错误原因,不包含用户信息。
限制
- 302 目标是否可匿名访问取决于存储策略配置;存储桶非公开时,图片链接可能返回 403。
no-store等禁止缓存头只作用于插件的 302 响应;目标图片的缓存策略由附件存储服务和 CDN 决定,插件无法保证目标图片不被缓存。- 附件列表采用短 TTL 缓存,新上传/删除的图片最多延迟一个缓存周期生效。
- 不包含访问鉴权、限流和图片代理下载;接口默认公开。
- 如果配置的路径与主题页面或文章永久链接完全冲突,主题路由可能优先匹配,请更换路径。
开发
构建、本地运行和端到端测试说明见 DEVELOPMENT.md。
反馈与支持
- 问题反馈:GitHub Issues
- 源码仓库:GitHub
- 作者主页:https://litx.cn
