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

无需Express实现Server-Sent Events:在线时长统计网站搭建方法咨询

不用Express实现基于Server-Sent Events的在线时长统计网页

当然可以不用Express,直接用Node.js原生的http模块就能实现Server-Sent Events(SSE),进而完成在线时长统计功能。下面是具体实现步骤:

一、服务端代码(Node.js)

创建一个server.js文件,用原生http模块搭建SSE服务,同时维护用户的在线时长:

const http = require('http');
const url = require('url');

// 存储用户在线时长,key为用户标识,value为开始时间戳
const userOnlineRecords = new Map();

const server = http.createServer((req, res) => {
  const parsedUrl = url.parse(req.url);

  // 处理SSE请求
  if (parsedUrl.pathname === '/sse') {
    // 设置SSE相关响应头
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
      // 允许跨域(如果客户端和服务端不在同一端口/域名)
      'Access-Control-Allow-Origin': '*'
    });

    // 生成唯一用户标识(这里用请求IP+随机数简单实现,生产环境可改用session或token)
    const userId = `${req.socket.remoteAddress}-${Math.random().toString(36).slice(2, 10)}`;
    // 记录用户上线时间
    userOnlineRecords.set(userId, Date.now());

    // 首次发送当前时长(初始为0)
    res.write(`data: {"userId": "${userId}", "onlineSeconds": 0}\n\n`);

    // 定时推送更新(每1秒发送一次)
    const intervalId = setInterval(() => {
      const startTime = userOnlineRecords.get(userId);
      const onlineSeconds = Math.floor((Date.now() - startTime) / 1000);
      // SSE消息格式:data: 内容\n\n
      res.write(`data: {"userId": "${userId}", "onlineSeconds": ${onlineSeconds}}\n\n`);
    }, 1000);

    // 监听客户端断开连接事件,清理记录和定时器
    req.on('close', () => {
      clearInterval(intervalId);
      userOnlineRecords.delete(userId);
      console.log(`用户 ${userId} 已下线`);
    });
  } 
  // 处理静态页面请求
  else if (parsedUrl.pathname === '/') {
    res.writeHead(200, {'Content-Type': 'text/html'});
    // 直接返回客户端HTML内容,也可以读取本地文件,这里为了简化直接写在代码里
    res.end(`
      <!DOCTYPE html>
      <html>
      <head>
        <title>在线时长统计</title>
        <style>
          body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }
          .duration { font-size: 2em; color: #2c3e50; margin-top: 20px; }
        </style>
      </head>
      <body>
        <h1>当前在线时长</h1>
        <div class="duration">0 秒</div>
        <script>
          // 客户端SSE连接代码
          const eventSource = new EventSource('http://localhost:3000/sse');
          const durationEl = document.querySelector('.duration');

          eventSource.onmessage = function(e) {
            const data = JSON.parse(e.data);
            durationEl.textContent = \`\${data.onlineSeconds} 秒\`;
          };

          eventSource.onerror = function(e) {
            console.error('SSE连接出错:', e);
            eventSource.close();
          };
        </script>
      </body>
      </html>
    `);
  } 
  // 404处理
  else {
    res.writeHead(404);
    res.end('Not Found');
  }
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(`服务运行在 http://localhost:${PORT}`);
});

二、代码说明

服务端核心逻辑

  1. SSE响应头设置:必须指定Content-Type: text/event-stream,同时禁用缓存、保持长连接。
  2. 用户标识与时长记录:用Map存储每个用户的上线时间戳,客户端断开时清理记录。
  3. 定时推送:通过setInterval每秒计算一次在线时长,以SSE格式推送给客户端。
  4. 静态页面返回:直接在服务端返回客户端HTML,避免额外的文件读取操作(简单场景下可用)。

客户端核心逻辑

  1. EventSource连接:创建EventSource实例连接服务端的SSE接口。
  2. 接收消息更新UI:监听onmessage事件,解析服务端发送的JSON数据,更新页面上的时长显示。
  3. 错误处理:监听onerror事件,连接出错时关闭SSE连接。

三、运行步骤

  1. 确保已安装Node.js环境。
  2. 将上述代码保存为server.js。
  3. 在终端执行node server.js启动服务。
  4. 打开浏览器访问http://localhost:3000,即可看到实时更新的在线时长。

四、注意事项

  • 跨域问题:如果客户端和服务端不在同一域名/端口,服务端需要设置Access-Control-Allow-Origin头,示例中已添加。
  • 用户标识优化:示例中的用户标识是简单的IP+随机数,生产环境建议使用更可靠的方式(如用户登录后的token、session ID)。
  • 资源清理:客户端断开连接时,服务端必须清理对应的定时器和用户记录,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 13:44:51