Kiwi IRC 1.7.1 嵌入与集成使用详解

Kiwi IRC 1.7.1 嵌入与集成实测:iframe 嵌入门户页并完成入频交互、邀请链接(URL hash IRC URI)全语法与 direct 形态边界实测、配置模板变量 {{hostname}}/{{port}} 展开、插件双形态加载机制与自定义启动屏注册。

Kiwi IRCKiwi IRCIRC即时通讯2026/10/26

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 副本多目录部署。

八、参考链接与站内文档

站内相关文档: