You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Node/Express将命令行输出的Twitch聊天内容展示到HTML页面

Twitch聊天流网页展示实现方案

核心问题说明

现有实现基于普通HTTP请求响应逻辑,服务端返回完twitch-chat.html页面后,和前端的连接就会断开,后续tmi.js拉取到的新聊天消息没有持续传输通道,因此只能在服务端控制台打印,无法同步到网页。要实现实时消息推送,采用WebSocket方案即可,新手优先选Socket.IO,对接成本极低,不需要手写底层WebSocket逻辑。


具体实现步骤

1. 安装所需依赖

执行命令安装Socket.IO:

npm install socket.io

注意:原有代码里bodyParser.urlEncoded存在拼写错误,正确写法是bodyParser.urlencoded,否则会导致表单参数解析失败。原有index.html表单逻辑不需要修改,可直接复用。

2. 改造后端服务(app.js)

把Express服务和Socket.IO绑定,前端连接后传入要监听的频道名,服务端创建tmi客户端拉取聊天消息,每收到一条消息就通过WebSocket推送给前端。
改造后的完整代码:

const express = require("express");
const bodyParser = require("body-parser");
const tmi = require("tmi.js");
const { createServer } = require("http");
const { Server } = require("socket.io");

const app = express();
// 创建HTTP服务绑定Socket.IO
const httpServer = createServer(app);
const io = new Server(httpServer);

app.use(express.static("public"));
// 修正原拼写错误:urlencoded 不是 urlEncoded
app.use(bodyParser.urlencoded({
    extended: true
}));

const port = 3000;

// 首页表单路由
app.get("/", (req, res) => {
    res.sendFile(__dirname + "/index.html");
});

// 表单提交处理,把频道名拼到URL参数传给前端
app.post("/", (req, res) => {
    const channelName = req.body.channelID.trim();
    res.redirect(`/chat?channel=${encodeURIComponent(channelName)}`);
});

// 聊天页渲染路由
app.get("/chat", (req, res) => {
    res.sendFile(__dirname + "/twitch-chat.html");
});

// 处理WebSocket连接
io.on("connection", (socket) => {
    let twitchClient = null;
    // 接收前端传过来的要监听的频道名
    socket.on("join-channel", (channelName) => {
        // 初始化tmi客户端
        twitchClient = new tmi.Client({
            connection: {
                secure: true,
                reconnect: true
            },
            channels: [channelName]
        });
        twitchClient.connect();
        // 收到Twitch聊天消息时推送给前端
        twitchClient.on('message', (channel, tags, message, self) => {
            const chatItem = {
                username: tags['display-name'],
                content: message,
                color: tags.color || '#9147ff' // 无自定义颜色的用户默认用Twitch品牌紫
            };
            // 把消息推给当前连接的前端
            socket.emit("new-chat-message", chatItem);
            console.log(`${chatItem.username}: ${chatItem.content}`);
        });
    });

    // 前端断开连接时关闭tmi客户端,避免资源浪费
    socket.on("disconnect", () => {
        if (twitchClient) twitchClient.disconnect();
    });
});

httpServer.listen(port, () => {
    console.log(`Server is running on ${port}!`);
})

3. 改造前端聊天页(twitch-chat.html)

页面加载后先从URL里拿到频道名,连接Socket.IO服务加入对应频道,每收到服务端推的新消息就追加到页面上,实现只读展示即可。
改造后的完整代码:

<!DOCTYPE html>
<html>
<head>
    <title>Twitch Chat</title>
    <style>
        .chat-container {
            max-width: 800px;
            margin: 2rem auto;
            border: 1px solid #efeff1;
            border-radius: 8px;
            height: 70vh;
            overflow-y: auto;
            padding: 1rem;
            font-family: sans-serif;
        }
        .chat-item {
            margin: 0.5rem 0;
            line-height: 1.5;
        }
        .username {
            font-weight: bold;
            margin-right: 0.5rem;
        }
        footer {
            text-align: center;
            margin-top: 2rem;
        }
    </style>
</head>
<body>
    <div class="chat-container" id="chatContainer"></div>

    <footer>
        <p>&copy; Drake Hopkins</p>
        <p>Built with tmi.js</p>
    </footer>

    <!-- 引入Socket.IO客户端脚本,服务端集成后会默认提供该静态资源 -->
    <script src="/socket.io/socket.io.js"></script>
    <script>
        const socket = io();
        const chatContainer = document.getElementById('chatContainer');
        // 从URL参数里拿到要监听的频道名
        const urlParams = new URLSearchParams(window.location.search);
        const channelName = urlParams.get('channel');

        // 连接成功后加入对应频道
        socket.on('connect', () => {
            socket.emit('join-channel', channelName);
        });

        // 收到新聊天消息时渲染到页面
        socket.on('new-chat-message', (chatItem) => {
            const itemDom = document.createElement('div');
            itemDom.className = 'chat-item';
            itemDom.innerHTML = `<span class="username" style="color: ${chatItem.color}">${chatItem.username}:</span><span class="message">${chatItem.content}</span>`;
            chatContainer.appendChild(itemDom);
            // 自动滚动到最新消息
            chatContainer.scrollTop = chatContainer.scrollHeight;
        });
    </script>
</body>
</html>

后续可选优化(新手阶段可暂时跳过)

  • 增加tmi客户端缓存,多个用户监听同一个频道时复用同一个连接,减少资源消耗
  • 增加Twitch表情、徽章的解析展示逻辑
  • 增加异常提示,对频道不存在、连接失败等场景给用户明确反馈
  • 给聊天消息增加时间戳展示

内容的提问来源于stack exchange,提问作者Drake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 02:51:21