const path = require('path') const db = require("../plugin/DataBase/db") const Logger = require('./Logger') const ipSearcher = require('../plugin/ip2region') class RequestLog { constructor() { this.logger = new Logger() this.searcher = ipSearcher.newWithFileOnly(path.join(__dirname, '../plugin/ip2region/ip2region.xdb')) } async insertLog(req, resData, namespace, method, path) { try { const time = new Date().getTime() const ip = this.getClientIp(req) let ipData = await this.searcher.search(ip) ipData = ipData.region const userAgent = req.headers['user-agent'] const deviceType = req.headers['device-type'] ?? '浏览器' let reqData if (method === 'get') { reqData = req.query } else { reqData = req.body } let sql = 'INSERT INTO requestLog (create_user, create_time, method, reqData, resData, code, ip, ua, deviceType, apiName, location, url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' let r = await db.query(sql, [reqData.uuid ?? '', time, method, reqData ?? {}, resData, resData.code, ip, userAgent, deviceType, namespace ?? '未知', ipData ?? '未知', path]) if (!r || r.affectedRows !== 1) this.logger.error(`插入日志信息失败!数据库错误`) } catch (error) { this.logger.error(`插入日志信息失败!${error}`) } } getClientIp(req) { let ip = null if (req.headers['x-forwarded-for']) { ip = req.headers['x-forwarded-for'].split(',')[0].trim(); } else if (req.headers['x-real-ip']) { ip = req.headers['x-real-ip']; } else { ip = req.connection.remoteAddress || '' } // 如果是 IPv6 映射的 IPv4 (::ffff:x.x.x.x),提取后面的 IPv4 if (ip.startsWith("::ffff:")) { ip = ip.replace("::ffff:", "") } // 如果是 [::1] 或其他 IPv6 const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/ if (!ipv4Regex.test(ip)) { return '0.0.0.0'; // 非 IPv4 } return ip ?? '0.0.0.0'; } } module.exports = RequestLog