index.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. const express = require('express');
  2. const mysql = require('mysql2');
  3. const cors = require('cors');
  4. require('dotenv').config();
  5. const app = express();
  6. const port = 3888;
  7. // 允许跨域
  8. app.use(cors());
  9. // 解析 JSON 请求体
  10. app.use(express.json());
  11. // 配置 MySQL 连接
  12. const db = mysql.createConnection({
  13. host: process.env.DB_HOST,
  14. user: process.env.DB_USER,
  15. port: process.env.DB_PORT,
  16. password: process.env.DB_PASSWORD,
  17. database: process.env.DB_NAME
  18. });
  19. db.connect((err) => {
  20. if (err) {
  21. console.error('数据库连接失败:', err);
  22. } else {
  23. console.log('已连接到MySQL数据库');
  24. }
  25. });
  26. // 插入数据接口
  27. app.post('/api/insert', (req, res) => {
  28. const {
  29. utm_source,
  30. utm_medium,
  31. utm_campaign,
  32. utm_term,
  33. utm_content,
  34. referrer,
  35. isMobile,
  36. browser,
  37. userAgent,
  38. osType,
  39. osVersion,
  40. timestamp,
  41. url
  42. } = req.body;
  43. const userId = req.headers.userid;
  44. const sql = `INSERT INTO data (
  45. utm_source,
  46. utm_medium,
  47. utm_campaign,
  48. utm_term,
  49. utm_content,
  50. referrer,
  51. is_mobile,
  52. browser,
  53. user_agent,
  54. os_type,
  55. os_version,
  56. timestamp,
  57. url,
  58. user_id
  59. ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
  60. const params = [
  61. utm_source || '',
  62. utm_medium || '',
  63. utm_campaign || '',
  64. utm_term || '',
  65. utm_content || '',
  66. referrer || '',
  67. isMobile ? 1 : 0,
  68. browser || '',
  69. userAgent || '',
  70. osType || '',
  71. osVersion || '',
  72. timestamp || '',
  73. url || '',
  74. userId || '',
  75. ];
  76. db.query(sql, params, (err, result) => {
  77. if (err) {
  78. console.error('数据库插入失败:', err);
  79. return res.status(500).json({ error: '数据库插入失败', details: err.message });
  80. }
  81. res.json({
  82. success: true,
  83. code: 200,
  84. id: result.insertId,
  85. message: '数据插入成功'
  86. });
  87. });
  88. });
  89. // 记录每个用户的最后心跳时间和心跳毫秒数
  90. const userHeartbeats = new Map();
  91. // 兼容 sendBeacon 和普通 POST 的插入日志接口
  92. app.post('/api/log', express.raw({ type: '*/*' }), (req, res) => {
  93. let data = {};
  94. // console.log(req.headers);
  95. // 读取心跳毫秒数(推荐用小写横线风格)
  96. const heartbeatMilliseconds = parseInt(req.headers['heartbeatseconds'], 10) || 10000;
  97. // 1. 先尝试直接用 req.body(普通 fetch/postman 情况)
  98. if (typeof req.body === 'object' && !(req.body instanceof Buffer)) {
  99. data = req.body;
  100. } else {
  101. // 2. sendBeacon 情况,body 是 Buffer,需要手动解析
  102. try {
  103. const jsonStr = req.body.toString();
  104. data = JSON.parse(jsonStr);
  105. } catch (e) {
  106. return res.status(400).json({ error: '无法解析请求体', details: e.message });
  107. }
  108. }
  109. // 获取用户唯一标识(这里用前端传输过来的请求头中的 userId)
  110. const userId =req.headers.userid;
  111. const now = Date.now();
  112. const last = userHeartbeats.get(userId);
  113. // 判断是否超时(直接用毫秒数)
  114. if (last && now - last.lastHeartbeat > last.heartbeatMilliseconds) {
  115. console.log(`用户 ${userId} 离开,最后心跳时间:${new Date(last.lastHeartbeat).toISOString()}`);
  116. }
  117. // 更新心跳
  118. userHeartbeats.set(userId, {
  119. lastHeartbeat: now,
  120. heartbeatMilliseconds
  121. });
  122. const {
  123. eventType,
  124. text,
  125. timestamp
  126. } = data;
  127. const sql = `INSERT INTO log (
  128. event_type,
  129. text,
  130. timestamp,
  131. user_id
  132. ) VALUES (?, ?, ?, ?)`;
  133. const params = [
  134. eventType || '',
  135. text || '',
  136. timestamp || new Date().toISOString(),
  137. userId
  138. ];
  139. db.query(sql, params, (err, result) => {
  140. if (err) {
  141. console.error('数据库插入失败:', err);
  142. return res.status(500).json({ error: '数据库插入失败', details: err.message });
  143. }
  144. res.json({
  145. success: true,
  146. code: 200,
  147. id: result.insertId,
  148. message: '数据插入成功'
  149. });
  150. });
  151. });
  152. app.listen(port, () => {
  153. console.log(`服务器已启动,端口 ${port}`);
  154. });