Kiwi IRC 1.7.1 嵌入与集成使用详解
Kiwi IRC 1.7.1 嵌入与集成实测:iframe 嵌入门户页并完成入频交互、邀请链接(URL hash IRC URI)全语法与 direct 形态边界实测、配置模板变量 {{hostname}}/{{port}} 展开、插件双形态加载机制与自定义启动屏注册。
Kiwi IRC 1.7.1 嵌入与集成使用详解
目标:讲清 Kiwi IRC 1.7.1 作为「可嵌入网页客户端」的完整集成面——iframe 嵌入第三方页面、URL 邀请链接(hash URI)直达连接、配置模板变量、插件加载机制与自定义启动屏。全部结论均为 2026-10-26 源码实查(v1.7.1)与本地浏览器(Chromium 无头模式)实测所得。
为什么本组件没有「CLI 使用」篇:Kiwi IRC 1.7.1 是纯静态前端(构建产物为 index.html + static/ 目录),没有任何命令行界面或服务端常驻进程,因此本专栏第四篇按组件形态写「嵌入与集成」,这也是官方 README 对该项目的第一定位(原文表述:如果你想把一个 IRC 客户端嵌入网站,可以用它自托管一个客户端)。
一、环境信息
| 项目 | 实测值 |
|---|---|
| 实测日期 | 2026-10-26 |
| 集成对象 | kiwiirc/kiwiirc v1.7.1(源码实查:src/main.js、src/helpers/Misc.js、src/components/startups/CustomServer.vue、src/components/App.vue) |
| 运行环境 | 与本专栏部署篇同环境:nginx 静态托管 + /ircws/ WebSocket 反代 + Ergo 2.7.0 对端,站点 http://192.168.146.131:8143/ |
| 浏览器实测 | Chromium(无头模式)驱动页面级交互:iframe 内连接入频、hash URI 表单预填与连接、模板变量展开 |
二、集成形态总览
| 形态 | 入口 | 适用 | 本篇 |
|---|---|---|---|
| iframe 嵌入 | 宿主页 <iframe src="客户端地址"> | 门户/控制台/文档站挂聊天区 | 第三章(实测) |
| 邀请链接 | URL hash 直接携带 IRC URI | 群发邀请、一键入频 | 第四章(实测) |
| 配置模板变量 | config.json 中写 {{hostname}} 等 | 一套配置适配多环境 | 第五章(实测) |
| 插件扩展 | config.json plugins 数组 | 定制界面/命令/协议行为 | 第六章 |
| 自定义启动屏 | 插件注册 startup | 完全定制首屏(品牌化) | 6.4 节 |
| 三种连接形态 | direct / 网关 / BNC | 服务端侧集成组织 | 配置篇第七章 |
三、iframe 嵌入(实测)
3.1 嵌入方式
Kiwi IRC 构建产物是自包含静态站,宿主页用一个 iframe 即可嵌入,无需引入任何脚本库:
<main>
<iframe id="kiwi-embed" src="http://192.168.146.131:8143/" allow="clipboard-write"></iframe>
</main>
实测宿主页为带侧栏的「社区门户」样式:顶部标题区 + 左侧频道导航 + 右侧整块 iframe。要点:
- iframe 高度建议
height: 100%(客户端本身撑满视口设计); - 嵌入形态下受同源策略约束最少的做法是客户端与宿主同域部署(本篇实测同源);跨域时需注意第六章插件的 fetch 加载与 iframe 通信限制;
allow="clipboard-write"用于放行复制消息的剪贴板权限。
3.2 实测结果
无头 Chromium 打开宿主页后逐项实读(逐行照抄):
[1] iframe.title = KiwiTest Web IRC
[1] iframe.form = true | inputs = 3
[1] button = "连接"
iframe 内完整加载了客户端(标题、三要素表单、连接按钮全部就位)。在 iframe 内填昵称 embeduser 并点「连接」,消息列表实测(逐行照抄):
Load previous messages
→ embeduser has joined
HistServ 07:51:42
embeduser joined the channel
嵌入态下连接、入频、发言与独立访问完全一致。
四、邀请链接:URL hash 携带 IRC URI(实测)
4.1 机制
在客户端地址后面以 URL hash 形式携带 IRC URI,customServer 启动屏会解析并自动填充连接参数(源码 components/startups/CustomServer.vue 实查:读 window.location.hash,先探测 irc:/ircs: 的 URL 编码形式再解析)。语法(源码 src/helpers/Misc.js 的 parseIrcUri 函数逐行实查):
#<连接串>[;<连接串>...]
连接串 = [(ircs|irc|ws|wss)://]主机[:[+]端口][/频道列表][?参数]
| 片段 | 说明 |
|---|---|
| irc:// / ircs:// | 网关形态(走 kiwiServer);ircs 表示 TLS |
| ws:// / wss:// | 直连形态(浏览器 WebSocket);wss 表示 TLS |
| 端口前加 + | TLS 标记(如 :+6697),等价 ircs |
| /频道列表 | 逗号分隔,无 # 前缀自动补(#help,#general 与 help,general 等价) |
| ?nick= | 昵称,支持 ? 随机数(见 4.3) |
| ?encoding= | 连接编码,默认 utf8 |
| ?type=znc&network= | ZNC bouncer 连接(network=_ 表示不支持网络的老版 ZNC) |
| 分号分隔多个连接串 | 一次性添加多个网络 |
示例:
http://192.168.146.131:8143/#ws://192.168.146.131:8143?nick=guest_?&channel=kiwitest
http://192.168.146.131:8143/#ircs://irc.example.com:+6697/help,general?nick=visitor_?
4.2 实测:单连接串行为
打开 http://10.89.57.1:8143/#ws://10.89.57.1:8143?nick=hashuser_?&channel=kiwitest,页面渲染的是精简连接表单——服务器框隐藏(值取自 URI),只留 Nick 与 Channel 两项,预填值实测(逐行照抄):
prefill: {"nickValue":"hashuser_33","allInputs":["hashuser_33","#kiwitest"]}
? 被替换为随机数 33(多开页面昵称天然错开);频道 kiwitest 自动补成 #kiwitest。此时用户仍需点「连接」确认,不会静默入频。
4.3 实测:direct 形态的重要边界
上例点「连接」后实测失败,页面显示(逐行照抄):
连接 KiwiTest IRC 网络
We couldn't connect to the server :(
Unknown error
Nick
I have a password
Channel
连接
原因(源码实查):CustomServer 的 hash URI 分支只设置 direct 标志,不读取 startupOptions.direct_path,WebSocket 直接连「主机:端口」的根路径 /;而本部署形态的 WS 反代挂在 /ircws/ 子路径(配置篇第七章),根路径返回的是 index.html,握手必然失败。
结论与规避:
| 场景 | 邀请链接 direct 形态 |
|---|---|
| WS 反代挂在站点根路径(location / 直接反代 ircd) | 可用 |
| WS 反代挂在子路径(如 /ircws/,本专栏部署形态) | hash URI 的 ws:// 形态不可用,改走网关形态(irc:// + webircgateway),或让用户从完整表单连接 |
这是 1.7.1 的实际行为(非配置错误),做「邀请链接」功能前务必先确认自己站点的反代路径形态。
五、配置模板变量(实测)
5.1 变量清单
config.json 的字符串值中可以使用以下模板变量,加载时由运行时替换(源码 src/main.js 实查):
| 变量 | 展开值 |
|---|---|
| {{protocol}} | 页面协议(http: / https:) |
| {{wsprotocol}} | https: 页面展开为 wss:,否则 ws: |
| {{tls}} | https: 页面展开为布尔 true,否则 false |
| {{hostname}} | 页面域名 |
| {{host}} | 页面域名:端口 |
| {{port}} | 页面端口(默认 80/443) |
| {{hash}} | 当前 URL hash(不含 #) |
| {{query}} | 当前 URL query(不含 ?) |
| {{referrer}} | document.referrer |
5.2 实测
把 config.json 的 startupOptions 改为 "server": "{{hostname}}"、"port": "{{port}}",无头 Chromium 打开站点后表单预填实测(逐行照抄):
[3] {{hostname}}/{{port}} 实测: {"serverBox":"(隐藏)","all":["10.89.57.1:8143","guest_37","#kiwitest"],"nick":"guest_37"}
server 展开为 10.89.57.1:8143——即浏览器视角的 hostname:port。这意味着同一份配置包在任意域名/端口下都自动指向「自己」,是构建通用部署包的关键机制(配置篇第八章的实测值即基于写死地址,两种写法按需选择)。实测后配置已还原。
六、插件机制
6.1 声明与加载
config.json 的 plugins 数组声明插件,页面加载完成后按序注入(源码 src/main.js 的 loadPlugins 函数实查):
"plugins": [
{ "name": "customise", "url": "static/plugins/customise.html" },
{ "name": "myplugin", "url": "static/plugins/myplugin.js" }
]
两种 URL 形态,加载方式不同(main.js 实查):
- .js 文件:以
<script>标签注入 body,加载失败只记控制台错误不阻断; - .html 文件:先 fetch 取回文本,塞入隐藏 div(id 为 kiwi_plugin_名称),再提取其中 script 逐个执行——即插件可以用 HTML 承载模板与脚本。
6.2 插件 API 入口
插件脚本通过 window.kiwi 对象获得运行时句柄(官方 Plugins wiki 约定),可挂接的状态事件由源码可见的 state.$emit 点位组成,常用如 irc.outgoing / irc.raw 等协议事件与 UI 组件注册。与协议层集成相关的两个源码事实:
- 发出的每条 IRC 消息都会经过 ircout 事件广播(src/libs/IrcClient.js 实查,raw() 被重载为「先发事件、事件未处理再走协议栈」),插件可拦截或改写;
- 连接层暴露 transport 注入点(network.connecting 事件中替换 eventObj.transport,IrcClient.js 实查)——这是非 direct/网关之外的第三种接入方式,适合自定义传输(如私有长连接网关)。
6.3 内置示例插件
构建产物自带 static/plugins/customise.html(配置篇第三章默认配置即引用它):提供界面级的定制示例,是学习插件写法的第一手参考。
6.4 自定义启动屏
插件可通过启动屏注册表添加全新首屏(src/components/App.vue 实查:startupScreen 取值来自组件注册表,包含内置五种 welcome/customServer/personal/kiwiBnc/znc,以及插件注册项)。配合 restricted 与品牌化主题,可实现完全定制的「站点即聊天入口」形态。配错 startupScreen 名会在控制台报 Startup screen "xxx" does not exist(配置篇 FAQ)。
七、嵌入场景常见问题(FAQ)
Q1:iframe 嵌入后点连接无反应或反复回到连接页? A:先用独立标签页打开客户端地址排除客户端本身问题;再检查 iframe 是否被浏览器拦截(第三方 Cookie/存储策略会影响状态持久化),同域部署最稳。
Q2:https 宿主页嵌 http 客户端? A:会被混合内容策略直接拦掉。整站 TLS:宿主 https、客户端 https、WebSocket 用 wss(config 的 tls: true,ircd 开 TLS 监听)。
Q3:邀请链接发出去,对方点了显示 We couldn't connect? A:见 4.3 边界——direct 形态的 hash URI 连根路径。确认反代路径形态:子路径反代时改用网关形态邀请链接,或把 WS 反代挪到根路径。
Q4:{{hostname}} 展开后还是连不上? A:变量展开的是「页面访问地址」,若 nginx 与 ircd 分机部署,页面地址与 IRC 连通地址不同,请写实际可达地址而不是模板变量。
Q5:插件加载了但不生效? A:看控制台是否出现 Error loading plugin '名称':URL 404(相对路径以站点根解析)或脚本异常。.html 形态插件要求与站点同源可 fetch。
Q6:想给不同页面嵌不同默认频道? A:同一部署下用 hash URI 的频道参数区分(#ws://host?nick=x&channel=a),或在宿主页用不同 config 副本多目录部署。
八、参考链接与站内文档
- Kiwi IRC 仓库:https://github.com/kiwiirc/kiwiirc
- 插件 wiki:https://github.com/kiwiirc/kiwiirc/wiki/Plugins
- 配置 wiki:https://github.com/kiwiirc/kiwiirc/wiki/Configuration
- v1.7.1 源码 parseIrcUri(本篇第四章语法溯源处):https://github.com/kiwiirc/kiwiirc/blob/v1.7.1/src/helpers/Misc.js
- webircgateway:https://github.com/kiwiirc/webircgateway
- KiwiBNC:https://github.com/kiwiirc/kiwibnc
站内相关文档: