fix: 修复添加记录后首页数据不刷新的问题
将缓存清除逻辑从 stats.js 路由移至 app.js 全局中间件, 确保 records.js 路由的写操作也能触发缓存清除。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
d551841035
commit
ac2d21a5a0
@@ -5,6 +5,7 @@ const compression = require('compression');
|
||||
|
||||
const config = require('./config');
|
||||
const logger = require('./utils/logger');
|
||||
const { clearUserCache } = require('./utils/cache');
|
||||
const db = require('./db');
|
||||
const { router: authRouter, auth } = require('./routes/auth');
|
||||
const statsRouter = require('./routes/stats');
|
||||
@@ -30,6 +31,16 @@ app.use('/api', (req, res, next) => {
|
||||
next();
|
||||
});
|
||||
|
||||
// 全局缓存清除中间件:在写操作完成后清除用户缓存
|
||||
app.use('/api', (req, res, next) => {
|
||||
res.once('finish', () => {
|
||||
if (['POST', 'DELETE', 'PUT', 'PATCH'].includes(req.method) && req.user?.id) {
|
||||
clearUserCache(req.user.id);
|
||||
}
|
||||
});
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/api/contacts', auth, (req, res) => {
|
||||
const field = req.query.field;
|
||||
const allowed = ['boss', 'partner', 'source', 'destination'];
|
||||
|
||||
+2
-41
@@ -3,50 +3,11 @@ const db = require('../db');
|
||||
const config = require('../config');
|
||||
const logger = require('../utils/logger');
|
||||
const { getMonthRange, AppError, validateRequired, validateNumber, validateInList } = require('../utils/helpers');
|
||||
const { getCached } = require('../utils/cache');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 内存缓存(限制大小,基于LRU)
|
||||
const statsCache = new Map();
|
||||
const CACHE_TTL = config.cache.ttl;
|
||||
const MAX_CACHE_SIZE = config.cache.maxSize;
|
||||
|
||||
function getCached(key, fetchFn) {
|
||||
const cached = statsCache.get(key);
|
||||
if (cached && Date.now() - cached.ts < CACHE_TTL) {
|
||||
// LRU: move to end
|
||||
statsCache.delete(key);
|
||||
statsCache.set(key, cached);
|
||||
return Promise.resolve(cached.data);
|
||||
}
|
||||
if (statsCache.size >= MAX_CACHE_SIZE) {
|
||||
// Delete oldest entry
|
||||
const firstKey = statsCache.keys().next().value;
|
||||
statsCache.delete(firstKey);
|
||||
}
|
||||
return Promise.resolve(fetchFn()).then(data => {
|
||||
statsCache.set(key, { data, ts: Date.now() });
|
||||
logger.debug(`缓存更新: ${key}`);
|
||||
return data;
|
||||
}).catch(err => {
|
||||
logger.error('缓存获取失败:', err.message);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
// POST/DELETE/PUT/PATCH 后清除当前用户的缓存
|
||||
router.use((req, res, next) => {
|
||||
res.once('finish', () => {
|
||||
if (['POST', 'DELETE', 'PUT', 'PATCH'].includes(req.method) && req.user?.id) {
|
||||
for (const key of statsCache.keys()) {
|
||||
if (key.includes(`:${req.user.id}:`)) {
|
||||
statsCache.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
next();
|
||||
});
|
||||
// 缓存模块已移至 utils/cache.js
|
||||
|
||||
// 格式化本地日期为 YYYY-MM-DD
|
||||
function formatLocalDate(date) {
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 统计数据缓存模块
|
||||
* 基于 LRU 算法的内存缓存
|
||||
*/
|
||||
const config = require('../config');
|
||||
const logger = require('./logger');
|
||||
|
||||
const statsCache = new Map();
|
||||
const CACHE_TTL = config.cache.ttl;
|
||||
const MAX_CACHE_SIZE = config.cache.maxSize;
|
||||
|
||||
/**
|
||||
* 获取缓存数据,如果不存在则通过 fetchFn 获取并缓存
|
||||
* @param {string} key 缓存键
|
||||
* @param {Function} fetchFn 获取数据的函数
|
||||
* @returns {Promise} 缓存数据
|
||||
*/
|
||||
function getCached(key, fetchFn) {
|
||||
const cached = statsCache.get(key);
|
||||
if (cached && Date.now() - cached.ts < CACHE_TTL) {
|
||||
// LRU: move to end
|
||||
statsCache.delete(key);
|
||||
statsCache.set(key, cached);
|
||||
return Promise.resolve(cached.data);
|
||||
}
|
||||
|
||||
// 超出最大缓存数量时,删除最旧的条目
|
||||
if (statsCache.size >= MAX_CACHE_SIZE) {
|
||||
const firstKey = statsCache.keys().next().value;
|
||||
statsCache.delete(firstKey);
|
||||
}
|
||||
|
||||
return Promise.resolve(fetchFn()).then(data => {
|
||||
statsCache.set(key, { data, ts: Date.now() });
|
||||
logger.debug(`缓存更新: ${key}`);
|
||||
return data;
|
||||
}).catch(err => {
|
||||
logger.error('缓存获取失败:', err.message);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定用户的所有缓存
|
||||
* @param {number} userId 用户ID
|
||||
*/
|
||||
function clearUserCache(userId) {
|
||||
const prefix = `:${userId}:`;
|
||||
for (const key of statsCache.keys()) {
|
||||
if (key.includes(prefix)) {
|
||||
statsCache.delete(key);
|
||||
logger.debug(`缓存清除: ${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有缓存
|
||||
*/
|
||||
function clearAllCache() {
|
||||
statsCache.clear();
|
||||
logger.debug('所有缓存已清除');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getCached,
|
||||
clearUserCache,
|
||||
clearAllCache
|
||||
};
|
||||
Reference in New Issue
Block a user