浏览器不支持(未启用)JavaScript,本页面的某些功能无法正常使用

Matrix 评论系统:我为 Cactus Comments 开发了些新功能

Divider Line

Cactus Comments 是一款独特的开源评论系统,它利用去中心化通讯协议 Matrix 作为后端,这赋予了它超越传统评论组件的巨大潜力——无论是实现网站实时聊天、集成 AI 智能客服,还是作为微博客(Microblog)的内容发布渠道,其扩展性在同类开源项目中都难得一见。

然而,原项目已停止更新,我为其注入了新的活力:不仅修复了原有缺陷,更独立开发了一系列实用新功能(我的分支目前尚未合并到主干)。

经过持续打磨,这个新版本已经相当完善。本文将为你详细介绍我带来的新特性,并提供一份结合新功能的中文安装教程。你可以在我的个人博客上体验。

请注意:为了服务器的稳定,体验前需要注册。因为访客模式可能会对自托管的 Matrix 服务端造成难以预估的压力。

新版 Cactus Comments:都有哪些亮点?

🚀 核心升级

  • 架构更新:重构了构建配置和依赖,现已支持在 Node.js v22+ 环境下进行开发和部署。

🖼️ 媒体功能大升级

  1. 安全媒体支持:新增 isAuthenticated 选项,当你的 Matrix 服务端启用媒体认证后,评论系统将通过认证端点请求媒体资源,并利用缓存优化加载速度。未认证状态下则沿用原始链接。

  2. 三级媒体缓存系统:为了更好的加载体验,我设计了一套缓存策略。

    • IndexedDB 持久化缓存:将媒体链接、文件数据、时间戳和类型存储在浏览器数据库中,并会自动清理超过一天的过期缓存。

    • 智能读取策略

      1. 内存缓存优先:最快响应。

      2. IndexedDB 次之:秒开已缓存的媒体。

      3. 网络获取保底:最后从服务器拉取。

💬 完整的消息回复功能

  1. 实现引用回复:现在支持消息间的引用关系,无论是普通回复还是在线程中回复,都能清晰地展示上下文。

  2. 动态加载与显示:对于已加载的引用,会显示其内容摘要;对于未加载的,会先提示“尚未加载”,一旦加载完成便自动更新,体验流畅。

  3. 悬停预览与跳转

    • 交互优化:鼠标悬停在引用上时,会立即弹出预览框(支持文本、图片、视频),让你一目了然。

    • 精准跳转:点击引用,页面会自动滚动到原始消息位置并高亮显示。

  4. 编辑器集成:在编辑器中即可发起引用回复,引用的内容会清晰地显示在编辑框上方。

🔒 只读模式

  • 新增 commentEnabled 配置项(默认为 true)。当设置为 false 时,评论区将变为只读模式,隐藏所有编辑和发送按钮,适用于内容展示或归档场景。

  • 注意:即便在只读模式下,访客自动注册功能依然是必需的(只在用户客户端首次访问网站的时候),这能确保用户可以正常查看历史消息和访问需要认证的媒体。如果你的网站访问量较大,最好为其增加权限,例如仅会员可见。

🌐 全面的多语言支持

  • 语言切换:新增 language 配置项,允许你自由设定显示语言。

  • 灵活的翻译方案:使用独立的 JS 或 JSON 文件管理翻译,并支持三种智能回退机制:

    1. 优先使用 translationsData 配置项引用的 JS 翻译文件。

    2. 其次尝试加载站点下的 /language/{lang}.json 语言文件。

    3. 最后默认显示英文,保证可用性。

✨ 前端渲染与体验修复

  1. 核心样式修复

    • 解决了嵌套 flex 布局下元素如代码块溢出的问题。

    • 限制了音频播放器的最大宽度,防止破坏页面布局。

    • 改进了文本换行逻辑,能正确处理长单词和 <em> 等标签内的换行。

  2. 评论列表性能优化

    • 防止重复加载:在加载过程中,“查看更多”按钮会被禁用,有效避免了并发请求和重复渲染消息。

    • 增量加载:现在点击“查看更多”只会追加新评论,而不是刷新整个评论区,避免闪烁和媒体播放状态重置。

横向对比与功能演示

与其他 Matrix 应用对比

我只选取了同样基于 Matrix 协议的嵌入式应用进行比较,以凸显新版 Cactus 的优势。

项目 嵌入方式 功能支持情况 特点 最后发布日期
Cactus 盒子元素 反应 ❌
私聊 ❌
访客 ✔️
登录 ✔️
附件上传 ❌
媒体显示 ✔️
媒体认证(此分支) ✔️
回复(此分支) ✔️
只读(此分支) ✔️
国际化(此分支) ✔️
简洁易用
功能丰富
没有明显的BUG
原项目:2022 年 7 月 8
此分支:持续更新
Chatterbox 气泡按钮 反应 ✔️
私聊 ✔️
访客(服务号) ✔️
登录 ❌
附件上传 ✔️
媒体显示 ✔️
媒体认证 ❌
回复❌
只读❌
国际化❌
支持反应和附件上传
使用应用程序服务注册账号而非访客模式
2022 年 10 月 17
Livematrix 气泡按钮 反应 ❌
私聊 ✔️
访客 ✔️
登录 ❌
附件上传 ❌
媒体显示 ✔️
媒体认证 ❌
回复❌
只读❌
国际化❌
2022 年 6 月 6

如果用作在网页独立区域展示的评论系统、短内容发布频道,推荐 Cactus Comments ,如果用作客服系统、消息气泡,Chatterbox 也许是更好的选择。

类似的项目还有:

  • hydrogen-web,这是个轻量级的 Matrix web 客户端,有 SDK 可以用来开发嵌入式前端,受限于 hydrogen 自身的实现, 访客、投票、消息列等尚未支持,优点是这是由element.io 组织托管和项目仍在持续更新。
  • Chatrix,功能丰富,只适用于 WordPress。
  • ceruleanMatrix Live,将 Matrix 房间发布为微博,功能较为简陋,可被Cactus完美替代。

以上大概就是全部了。

功能展示(截图)

  1. 图片和AI演示:

  1. 引用和引用预览演示
  2. 加载、夜间模式演示

安装教程

基础准备:引入脚本

无论采用何种部署方式,您都需要先获取项目文件。

  1. 前往 Cactus Comments 的 GitHub 分支项目 下载最新 release 版本。

  2. cactus.jsstyle.csscactus-lang.js 三个文件上传到您的服务器或 CDN。

  3. 在您网站的 HTML 页面中引入这些文件:

<link rel="stylesheet" href="https://.../.../cactus-style.css" type="text/css">
<script type="text/javascript" src="https://.../.../cactus.js"></script>
<script type="text/javascript" src="https://.../.../cactus-lang.js"></script>

快速入门:使用官方服务 (无需自建服务端)

步骤 1: 注册站点

与官方服务机器人 @cactusbot:cactus.chat 发起私聊,发送以下命令来注册您的站点:

register <YOUR-SITE-NAME>

请将 <YOUR-SITE-NAME> 替换为您网站的唯一英文名称。

步骤 2: 嵌入评论区

将以下代码嵌入到您网站需要显示评论区的页面。

<!-- 假设这是您网站页面上用来展示评论的描点元素 -->
<div id="comment-section"></div>

<script>
  // 初始化评论区
  initComments({
    // 必填参数
    node: document.getElementById("comment-section"),
    defaultHomeserverUrl: "https://matrix.cactus.chat:8448",
    serverName: "cactus.chat",
    siteName: "<YOUR-SITE-NAME>", // 替换为您注册的站点名称
    commentSectionId: "unique-page-id", // 每个页面的唯一ID,决定了评论所属的Matrix房间

    // 其他可选参数...
  });
</script>
  • siteName: 您在上一步注册的站点名称。

  • commentSectionId: 每个页面的唯一标识符。它将用于生成 Matrix 房间的别名。如果希望整个站点的所有页面共享同一个评论区,可以所有页面都使用相同的 ID。

  • 房间的消息预览将加载在id="comment-section"的评论区。

工作原理

  • 访客用户: 当用户首次访问页面时,系统会自动在 matrix.cactus.chat 服务器上为他们注册一个访客账户,并将凭证缓存在浏览器本地。

  • 房间创建: 当第一个访客访问时,服务机器人会自动创建一个公开的 Matrix 房间,别名格式为 #comments_siteName_commentSectionId:cactus.chat

  • 房间管理: 您用于注册站点的 Matrix 账号将成为该房间的管理员,可以修改房间名称、描述等,但不能更改加入和阅读权限。

服务提示: matrix.cactus.chat 是一个用于测试和快速体验的站点,不保证长期稳定。若服务中断,旧的访客账号将失效,且无法注册新访客或创建新评论房间。为了长期稳定使用,强烈建议自托管 Matrix 服务端

因为房间是联邦的,如果使用联邦管理账号启用联邦别名,在网页上修改serverName等参数对应房间别名,可以无缝切换到新的matrix homeserver 来承载这个评论房间,前提是新的服务端支持访客模式,如若需要自动创建新的评论房间,还应该在服务端部署Cactus Comments的应用程序服务,也就是需要有类似@cactusbot:cactus.chat的服务机器人。

前端自定义

可选的initComments参数:

名称 类型 必填 默认值 描述
node HTML 元素或字符串 - 页面上将被评论区替换的 HTML 元素。字符串作为选择器传递给 document.querySelector
defaultHomeserverUrl 字符串 - 含有 Cactus Comments 应用服务的 Matrix 主服务器 URL,不包含斜杠结尾。
serverName 字符串 - 含有 Cactus Comments 应用服务的 Matrix 主服务器名称,通常是 defaultHomeserverUrl 的域名部分。
siteName 字符串 - 您在 Cactusbot 注册的站点唯一标识符。
commentSectionId 字符串 - 评论区的唯一标识符,不能包含斜杠和下划线。
pageSize 整数 10 初始加载及每次点击“查看更多”时加载的评论数量。
loginEnabled 布尔值 true 若为 true,用户可使用 Matrix 凭据在页面登录;若为 false,登录按钮变为 Matrix.to 链接,跳转至 Matrix 客户端。
guestPostingEnabled 布尔值 true 若为 true,用户可无需登录以访客身份发表评论。
updateInterval 浮点数 0 获取新评论的时间间隔(秒)。若为零或负值,则不会自动获取更新。
isAuthenticated 布尔值 false 媒体认证功能
commentEnabled 布尔值 true false为评论区只读模式
translationsData 字符串 cactusTranslations cactusTranslations值在cactus-lang.js中定义,默认提供多语言版本,也可以自定义(单语言)翻译文件,在这个参数中引用。
language 字符串 en 符合ISO 639标准的语言代码,如cnfren

样式自定义

Cactus 前端项目有一个TODO:样式表,元素都可以自定义。

颜色模式

Cactus 前端预设了浅色和深色模式。默认情况下,样式表会根据浏览器选择的配色方案进行调整,因此你不需要做任何事情。如果想明确控制亮/暗模式,可以通过在 <html> 元素上设置 light 和 dark 类来覆盖它。

评论元素顺序调整
  1. 颠倒评论列表和编辑器的顺序,将评论列表置于顶部,编辑器置于底部,可以使用以下规则:
.cactus-container {
  flex-direction: column-reverse;
}
  1. 颠倒评论本身的顺序,将较旧的评论放在顶部,较新的评论放在底部,可以使用以下规则:
.cactus-comments-container {
  flex-direction: column-reverse;
}

.cactus-comments-list {
  flex-direction: column-reverse;
}

自托管部署(以 Synapse 为例)

步骤1. 启用访客模式

服务端使用 Synapse,其他Matrix服务端实现参考各自的官方说明。在homeserver.yaml配置中启用访客模式:allow_guest_access: true,由于当有大量访客时可能会给服务器带来额外负担,配置中有另外几个和guest账号相关的选项建议:

  • turn_allow_guests: false
  • auto_join_rooms_for_guests: true
  • send_server_notice_to_guests: false

此外,如果synapse启用了隐私政策:user_consent和其中的block_events_error,那么访客首次发送消息时会响应一条 错误信息,其中有包含用户id的隐私政策链接,需要用户手动复制链接打开,同意之后才能发送消息,为避免影响使用体验建议关闭,或者在独立的JS中为用户处理。

如果想对访客作出更多限制(例如自动过期、自动id名称前缀后缀),可以使用这个应用程序模块:restricted-guests

步骤2. 创建 Cactus Comments 应用程序服务

1. 创建Appservice 注册文件
# 应用服务的唯一自定义ID,永远不会改变。
id: "Cactus Comments"

# cactus-appservice 的托管地址
# 端口是后续安装的cactus-appservice容器映射到外部的端口,需要synapse服务可以访问到
# 例"http://localhost:5000"
url: "http://cactus:5000"

# 用于在我们的服务与主服务器之间(以及反向)认证请求的唯一令牌。请使用某些随机内容的 sha256 哈希值。
# 请更改这些值。
# 使用 `pwgen -syc 64 1` 或 `openssl rand -base64 32` (或更长) 直接生成 token
as_token: "a2d7789eedb3c5076af0864f4af7bef77b1f250ac4e454c373c806876e939cca"
hs_token: "b3b05236568ab46f0d98a978936c514eac93d8f90e6d5cd3895b3db5bb8d788b"

# 与我们的服务关联的用户。在本例中为 "@cactusbot:example.com"
sender_localpart: "cactusbot"

namespaces:
  aliases:
    - exclusive: true
      regex: "#comments_.*"
2. 在 Synapse 中注册 Appservice

cactus.yaml 文件复制到 Synapse 可以访问的目录,并在 homeserver.yaml 中引用它:

app_service_config_files:
  # /path/to/ synapse的内部目录
  - "/path/to/cactus.yaml"
3. 启用旧版 Appservice 授权 (重要)

Cactus Comments 的 Appservice 依赖一个较旧的授权机制。请在 homeserver.yaml 中添加以下配置,否则服务机器人将无法被创建,也无法注册站点。

use_appservice_legacy_authorization: true

旧版本的Matrix规范通过access_token查询参数来进行应用服务授权,此选项被认为是不安全的,从 Synapse v1.71.0 版本开始,应用服务令牌已通过 Authorization 标头发送,使得不安全的查询参数授权变得多余,此选项默认为 false,cactus-appservice依赖比较旧,需要要这个选项才能进行一些管理操作,包括:

  • 通过应用服务创建管理机器人账号。
  • 网站管理员通过这个机器人注册站点。
  • 机器人创建审核室,使用内置工具帮助用户进行审核,两个功能:
    1. 功率级复制,如果您邀请并提升某人到审核室,他们在您的所有评论房间中都将具有相同的权限部分。 作为一种简单的机制,可以让多人成为评论部分的版主。
    2. 禁止传播,如果你在你的评论区封禁了一个用户,他们将自动在你的所有评论区被封禁。

错误提示:当首次创建服务未启用该功能时,会在日志中出现INFO in app: 401 CHAT.CACTUS.APPSERVICE_UNAUTHORIZED ,机器人账号无法创建,提示不存在,自然也就无法注册站点和创建评论房间了,即便你手动创建账号也不行,必须通过应用服务。

如果你只需要一个评论房间应用到自己的网站上,后续可以关闭这个配置选项,机器人将无法再注册新的网站,无法为新的commentSectionId:创建房间,也无法使用内置的审核工具,不过已经启用的评论房间和访客模式不受影响。

步骤 3: 部署 Cactus Appservice 容器

docker-compose.yaml
services:
 # ... 您的 synapse 服务 ...
  cactus:
    image: cactuscomments/cactus-appservice:latest
    container_name: cactus
    restart: unless-stopped
    network_mode: host
    # 或者bridge模式,前面一个端口要和`cactus.yaml` 中的对应上
    # network_mode: bridge
    # ports:
    #   - 8500:5000
    environment:
      - "CACTUS_HS_TOKEN=xxx"
      - "CACTUS_AS_TOKEN=xxx"
      - "CACTUS_HOMESERVER_URL=https://matrix.domain.com:8448"
      - "CACTUS_USER_ID=@cactusbot:domain.com"
      - "CACTUS_NAMESPACE_REGEX=#comments_.*"
      - "CACTUS_NAMESPACE_PREFIX=comments_"
      - "CACTUS_REGISTRATION_REGEX=@userid:domain.com"
   # 如果和synapse一起部署,并且synapse 启用了healthcheck,建议加上这个
   # depends_on:
    #   synapse:
    #     condition: service_healthy
其中的环境变量
名称 是否必需 描述
CACTUS_HS_TOKEN 用于认证主服务器的令牌。此值应与注册 YAML 文件中的 hs_token 保持一致。
CACTUS_AS_TOKEN 用于将应用服务认证到主服务器的令牌。此值应与注册 YAML 文件中的 as_token 保持一致。
CACTUS_HOMESERVER_URL 应用服务注册到的主服务器的完整 URL。
CACTUS_USER_ID 聊天机器人接口的用户 ID。此值应基于注册 YAML 文件中的 sender_localpart,例如:@cactusbot:example.com
CACTUS_NAMESPACE_REGEX 应用服务控制的房间别名的正则表达式。此值应与注册 YAML 文件中的正则表达式保持一致。例如:#comments_.
CACTUS_NAMESPACE_PREFIX 应用服务控制的房间别名前缀。仅当设置了 CACTUS_NAMESPACE_REGEX 时才应设置,并且应与其保持一致。例如:comments_
CACTUS_REGISTRATION_REGEX 仅允许符合此正则表达式的用户 ID 注册新站点。例如:@user1:example.org @user2:example.org。

运行 docker-compose up -d 启动服务。现在,您可以像使用官方服务一样,与您自己的 @cactusbot:your-matrix-domain.com 机器人交互来注册站点和管理评论了。

附录:什么是Matrix 媒体认证

媒体认证 (Authenticated Media) 是 Matrix 的一项安全特性 (MSC3916),旨在解决非加密媒体文件可被任何人通过直链公开访问的问题。

在 Synapse 中,此功能通过 homeserver.yamlenable_authenticated_media 选项控制,默认已启用

  • 启用后:新上传的媒体文件将需要提供有效的 access_token (即使用户是访客) 才能访问,增强了隐私保护。

  • 启用前:已经存在的媒体文件不受影响,仍然可以公开访问。

当您在 initComments 中设置 isAuthenticated: true 时,Cactus Comments 会在请求媒体文件时附带用户的 access_token,从而能够正常显示受此特性保护的图片和文件。如果您的 Synapse 服务端启用了媒体认证,请务必开启此选项。

Divider Line
标签: Matrix 砖工技术
作者: 宁迦
日期:2025年06月08日

评论