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, res, namespace, method) { try { const time = new Date().getTime() const ip = this.getClientIp(req) const ipData = await this.searcher.search(ip).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, code, ip, ua, deviceType, apiName, location) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' let r = await db.query(sql, [reqData.uuid ?? '', time, method, reqData, res.code, ip, userAgent, deviceType, namespace ?? '未知', ipData]) 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 null; // 非 IPv4 返回 null 或者你可以保留原值 } return ip; } } module.exports = RequestLog