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

如何统计网站访客停留时长?适配AJAX+ExpressJS+MySQL的商城分析后台需求

Hey there! 作为商场经营者搭建数据分析后台确实需要贴合自己技术栈的方案,Cookie的思路没错,但结合你的AJAX+ExpressJS+MySQL技术栈,我们可以把流程优化得更精准流畅。下面是具体的实现步骤:

解决方案:用户停留时长统计与后台推送

1. 前端:精准跟踪停留时长并上报

因为你的网站用AJAX做无刷新跳转,传统依赖页面刷新的Cookie对比法不太适配,我们可以通过监听页面可见性变化和路由切换事件来统计实际有效停留时长:

// 初始化核心变量
let sessionStartTime = Date.now();
let isPageVisible = true;

// 监听页面切出/切回事件
document.addEventListener('visibilitychange', () => {
  isPageVisible = !document.hidden;
  if (isPageVisible) {
    sessionStartTime = Date.now(); // 用户回到页面时重置计时起点
  } else {
    // 用户切走时立即上报当前段停留时长
    reportStayDuration();
  }
});

// 监听页面卸载(关闭标签/手动刷新)
window.addEventListener('beforeunload', () => {
  reportStayDuration();
});

// 监听AJAX路由切换(根据你用的路由框架调整,比如Vue Router的beforeEach)
// 示例:假设你的路由切换会触发customRouteChange事件
window.addEventListener('customRouteChange', () => {
  reportStayDuration();
  sessionStartTime = Date.now(); // 切换页面后重置计时
});

// 核心上报函数
function reportStayDuration() {
  if (!isPageVisible) return;
  const stayDuration = Date.now() - sessionStartTime;
  // 过滤掉1秒以内的无效停留(避免误统计)
  if (stayDuration > 1000) {
    fetch('/api/report-stay', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        duration: stayDuration,
        pagePath: window.location.pathname, // 可选:统计不同页面的停留数据
        // 可选:加用户唯一标识(比如存在Cookie里的sessionId,用来区分单个用户)
        userId: document.cookie.split('; ').find(row => row.startsWith('sessionId=')).split('=')[1] || null
      })
    });
  }
}

2. 后端:ExpressJS接收数据并存储到MySQL

首先在MySQL里创建统计数据表:

CREATE TABLE user_stay_records (
  id INT AUTO_INCREMENT PRIMARY KEY,
  duration BIGINT NOT NULL, -- 停留时长(毫秒)
  page_path VARCHAR(255),
  user_id VARCHAR(64), -- 可选:用户唯一标识
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

然后在ExpressJS中编写接收上报的接口:

const express = require('express');
const mysql = require('mysql2/promise');
const app = express();

// 配置MySQL连接池
const pool = mysql.createPool({
  host: '你的数据库地址',
  user: '数据库用户名',
  password: '数据库密码',
  database: '你的数据库名',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

// 解析JSON请求体
app.use(express.json());

// 接收停留时长上报的接口
app.post('/api/report-stay', async (req, res) => {
  const { duration, pagePath, userId } = req.body;
  if (!duration) return res.status(400).send('缺少停留时长数据');

  try {
    const [result] = await pool.execute(
      'INSERT INTO user_stay_records (duration, page_path, user_id) VALUES (?, ?, ?)',
      [duration, pagePath, userId]
    );
    res.status(200).send('数据上报成功');
  } catch (err) {
    console.error('存储数据失败:', err);
    res.status(500).send('服务器内部错误');
  }
});

app.listen(3000, () => console.log('服务器运行在端口3000'));

3. 分析后台:计算并展示平均停留时长

写一个接口从MySQL中计算平均时长,供你的数据分析后台调用:

app.get('/api/average-stay', async (req, res) => {
  const { pagePath, startDate, endDate } = req.query;
  let query = 'SELECT AVG(duration) AS avg_duration FROM user_stay_records';
  const params = [];

  // 可选:按页面筛选
  if (pagePath) {
    query += ' WHERE page_path = ?';
    params.push(pagePath);
  }
  // 可选:按时间范围筛选
  if (startDate && endDate) {
    query += pagePath ? ' AND' : ' WHERE';
    query += ' created_at BETWEEN ? AND ?';
    params.push(startDate, endDate);
  }

  try {
    const [result] = await pool.execute(query, params);
    // 转换为秒更易读,默认0(无数据时)
    const avgSeconds = result[0].avg_duration ? Math.round(result[0].avg_duration / 1000) : 0;
    res.json({ average_stay_seconds: avgSeconds });
  } catch (err) {
    console.error('计算平均时长失败:', err);
    res.status(500).send('服务器内部错误');
  }
});

额外优化小技巧

  • 用户标识:可以在用户首次访问时生成一个唯一sessionId存在Cookie中,上报时一起传递,这样能统计单个用户的行为轨迹,而不只是全局平均。
  • 防抖处理:如果用户频繁切换标签页,可以给上报函数加防抖(比如10秒内只上报一次),减少无效请求。
  • 失败重试:前端上报失败时,把数据暂存到localStorage,下次页面加载时自动重试,避免数据丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:09:20