123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- const express = require('express');
- const mysql = require('mysql2');
- const cors = require('cors');
- require('dotenv').config();
- const app = express();
- const port = 3888;
- // 允许跨域
- app.use(cors());
- // 解析 JSON 请求体
- app.use(express.json());
- // 配置 MySQL 连接
- const db = mysql.createConnection({
- host: process.env.DB_HOST,
- user: process.env.DB_USER,
- port: process.env.DB_PORT,
- password: process.env.DB_PASSWORD,
- database: process.env.DB_NAME
- });
- db.connect((err) => {
- if (err) {
- console.error('数据库连接失败:', err);
- } else {
- console.log('已连接到MySQL数据库');
- }
- });
- // 插入数据接口
- app.post('/api/insert', (req, res) => {
- const {
- utm_source,
- utm_medium,
- utm_campaign,
- utm_term,
- utm_content,
- referrer,
- isMobile,
- browser,
- userAgent,
- osType,
- osVersion,
- timestamp,
- url
- } = req.body;
- const userId = req.headers.userid;
- const sql = `INSERT INTO data (
- utm_source,
- utm_medium,
- utm_campaign,
- utm_term,
- utm_content,
- referrer,
- is_mobile,
- browser,
- user_agent,
- os_type,
- os_version,
- timestamp,
- url,
- user_id
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
- const params = [
- utm_source || '',
- utm_medium || '',
- utm_campaign || '',
- utm_term || '',
- utm_content || '',
- referrer || '',
- isMobile ? 1 : 0,
- browser || '',
- userAgent || '',
- osType || '',
- osVersion || '',
- timestamp || '',
- url || '',
- userId || '',
- ];
- db.query(sql, params, (err, result) => {
- if (err) {
- console.error('数据库插入失败:', err);
- return res.status(500).json({ error: '数据库插入失败', details: err.message });
- }
- res.json({
- success: true,
- code: 200,
- id: result.insertId,
- message: '数据插入成功'
- });
- });
- });
- // 记录每个用户的最后心跳时间和心跳毫秒数
- const userHeartbeats = new Map();
- // 兼容 sendBeacon 和普通 POST 的插入日志接口
- app.post('/api/log', express.raw({ type: '*/*' }), (req, res) => {
- let data = {};
- // console.log(req.headers);
- // 读取心跳毫秒数(推荐用小写横线风格)
- const heartbeatMilliseconds = parseInt(req.headers['heartbeatseconds'], 10) || 10000;
-
- // 1. 先尝试直接用 req.body(普通 fetch/postman 情况)
- if (typeof req.body === 'object' && !(req.body instanceof Buffer)) {
- data = req.body;
- } else {
- // 2. sendBeacon 情况,body 是 Buffer,需要手动解析
- try {
- const jsonStr = req.body.toString();
- data = JSON.parse(jsonStr);
- } catch (e) {
- return res.status(400).json({ error: '无法解析请求体', details: e.message });
- }
- }
- // 获取用户唯一标识(这里用前端传输过来的请求头中的 userId)
- const userId =req.headers.userid;
- const now = Date.now();
- const last = userHeartbeats.get(userId);
- // 判断是否超时(直接用毫秒数)
- if (last && now - last.lastHeartbeat > last.heartbeatMilliseconds) {
- console.log(`用户 ${userId} 离开,最后心跳时间:${new Date(last.lastHeartbeat).toISOString()}`);
- }
- // 更新心跳
- userHeartbeats.set(userId, {
- lastHeartbeat: now,
- heartbeatMilliseconds
- });
- const {
- eventType,
- text,
- timestamp
- } = data;
- const sql = `INSERT INTO log (
- event_type,
- text,
- timestamp,
- user_id
- ) VALUES (?, ?, ?, ?)`;
- const params = [
- eventType || '',
- text || '',
- timestamp || new Date().toISOString(),
- userId
- ];
- db.query(sql, params, (err, result) => {
- if (err) {
- console.error('数据库插入失败:', err);
- return res.status(500).json({ error: '数据库插入失败', details: err.message });
- }
- res.json({
- success: true,
- code: 200,
- id: result.insertId,
- message: '数据插入成功'
- });
- });
- });
- app.listen(port, () => {
- console.log(`服务器已启动,端口 ${port}`);
- });
|