从小就很喜欢折腾论坛程序。
早些年接触最多的是 Discuz!、phpwind 这些经典 PHP 论坛。从下载安装到更换模板、添加插件、调整版块和用户组权限,最终也没什么人气,只是沉浸于搭建过程。
最近发现了
Rhex
,又产生了部署论坛的兴趣。项目提供 Docker 镜像,Web、Worker 和初始化任务的职责比较清楚;上传既可以使用本地目录,也能继续接入 S3、OSS 等对象存储。对已经使用 1Panel 和 Docker Compose 管理服务的人来说,部署和后续维护都比较直观。
程序本身的完成度已经很高,不过使用时很快遇到了一个比较具体的需求:用户上传的图片最好能在写入存储前自动压缩。
如果只是在某个上传接口里调用一次图片处理库,这件事并不复杂。但我更希望把它做成一个独立插件:后台可以配置压缩策略、尺寸、质量和输出格式;插件关闭后恢复原有上传流程;以后升级或调整参数时,也不需要继续修改论坛业务代码。
最终,这个需求不只产生了一个插件,还顺带补上了 Rhex 上传扩展点、修复了一个 PostgreSQL 上传错误,并解决了修改版生产镜像的依赖问题。
当然,上述全程离不开 AI 的支持。
如何压缩图片
Rhex 已经有一套插件系统,upload provider 也提供了 uploadFile()。不过它的用途是让插件接管最终存储,而不是在保存之前修改图片内容。
如果直接使用 uploadFile() 做图片压缩,插件就需要同时负责文件命名、配额、哈希去重、上传记录,以及 local、S3、OSS 等存储逻辑。这样不仅重复实现宿主已有能力,以后 Rhex 调整上传流程时,插件也很容易跟不上。
另外,现有的 upload.file.before action hook 可以在上传前执行动作,但不能把新的图片 Buffer 交回宿主,因此也无法承担压缩或转码工作。
比较合适的方式,是让插件只处理图片,把最终存储继续交给 Rhex。
给 upload provider 增加 transformFile()
我在 Rhex 宿主中增加了一个可选的 transformFile() hook。处理顺序变成:
上传格式与原始大小校验
-> Rhex 水印
-> 插件压缩、缩放或转码
-> 宿主重新检测真实 MIME、文件大小和 SHA-256
-> 去重与上传配额
-> local / S3 / OSS 保存
剩余 1 行代码
展开剩余代码
多个 upload provider 可以按照顺序串行处理图片。插件返回新的 Uint8Array 后,宿主会重新检查真实格式、文件大小和哈希,不会直接信任插件返回的文件信息。