데이터를 조작하는 경우, CUD를 시행한 브라우저에서는 캐시 데이터가 정상적으로 반영되는데, 타 브라우저(or 다른 컴퓨터)에는 즉각 데이터가 반영되지 않은 오류 발생.
아래의 코드에서 res.json = function으로 연결한 부분이 문제였을 가능성이 있음. 다음 프로젝트에서 확인 필요.
import { Request, Response, NextFunction } from "express";
import Redis from "ioredis";
// Redis 클라이언트 생성
const redis = new Redis({
host: process.env.NODE_ENV === "production" ? process.env.REDIS_HOST : "127.0.0.1",
port: Number(6379),
});
// 연결 상태 모니터링
redis.on("connect", () => console.log("✅ Redis 연결됨"));
redis.on("ready", () => console.log("✅ Redis 준비됨"));
redis.on("error", (err) => console.error("❌ Redis 오류: ", err));
// 캐싱 미들웨어 함수 (TTL을 매개변수로 받음)
export const cacheMiddleware = (ttl = 300) => {
return async (req: Request, res: Response, next: NextFunction) => {
try {
// 식별자
const userId = req.auth?.userId || undefined;
const locale = req.query.targetLang || "ko";
const cacheKey = `cache:${userId}:${locale}:${req.originalUrl}`;
// GET만 캐싱
if (req.method !== "GET") return next();
// Redis에서 캐시된 데이터 확인
const cachedData = await redis.get(cacheKey);
console.log("cachedData 여부", !!cachedData);
if (cachedData) {
// 캐시된 데이터가 있으면 반환
res.setHeader("X-Cache", "HIT");
const parsedData = JSON.parse(cachedData);
return res.status(200).json(parsedData);
}
// 캐시된 데이터가 없으면 원본 응답을 캐시하도록 설정
res.setHeader("X-Cache", "MISS");
const originalJson = res.json;
res.json = function (data) {
// 응답 데이터를 Redis에 캐시 (TTL 설정)
if (res.statusCode === 200) {
// 200만 캐싱
redis.setex(cacheKey, ttl, JSON.stringify(data));
}
// 원본 json 메서드 호출
return originalJson.call(this, data);
};
next();
} catch (error) {
console.error("Cache middleware error:", error);
// 오류가 발생해도 애플리케이션은 계속 동작하도록 next() 호출
next();
}
};
};
// 캐시 무효화 미들웨어 함수 (특정 URL만 무효화)
export const invalidateCache = (targetUrls?: string) => {
return async (req: Request, res: Response, next: NextFunction) => {
try {
// 특정 캐시만 삭제(식별자)
const userId = req.auth?.userId || undefined;
const locale = req.query.targetLang || "ko";
if (targetUrls && targetUrls.length > 0) {
for (const url of targetUrls) {
const cacheKey = `cache:${userId}:${locale}:${url}`;
await redis.del(cacheKey);
console.log(`Invalidated cache for: ${cacheKey}`);
}
} else {
// 사용자별 모든 캐시 삭제 (패턴 매칭)
const pattern = `cache:${userId}:${locale}:*`;
const keys = await redis.keys(pattern);
if (keys.length > 0) {
await redis.del(...keys);
console.log(`Invalidated ${keys.length} cache entries for user: ${userId}`);
}
}
next();
} catch (error) {
console.error("Cache invalidation error:", error);
next();
}
};
};