Next.js 15如何配置Redis自定义缓存?@neshca工具兼容问题求助
解决方案:自定义Next.js 15缓存处理器实现Redis+LRU降级
由于@neshca/cache-handler暂未适配Next.js 15的缓存API变更,我们可以通过自定义缓存处理器实现需求,以下是完整落地方案:
1. 依赖准备
安装核心依赖包:
npm install redis lru-cache # 或 yarn add redis lru-cache
2. 实现自定义缓存处理器
在项目根目录的app文件夹下创建cache-handler.ts,实现Redis+LRU自动降级逻辑:
import { createClient } from 'redis'; import LRU from 'lru-cache'; import type { CacheHandler } from 'next/dist/server/web/spec-extension/cache-handler'; // 初始化Redis客户端 const redisClient = createClient({ url: process.env.REDIS_URL || 'redis://localhost:6379', }); // 标记Redis可用性,连接失败时自动切换到LRU let redisAvailable = true; redisClient.on('error', () => (redisAvailable = false)); redisClient.connect().catch(() => (redisAvailable = false)); // 初始化LRU本地缓存,可根据业务调整配置 const lruCache = new LRU({ max: 1000, // 最大缓存条目数 ttl: 60 * 60 * 1000, // 默认1小时过期 }); const cacheHandler: CacheHandler = { // 获取缓存 async get(key: string) { try { if (redisAvailable) { const value = await redisClient.get(key); if (value) return JSON.parse(value); } return lruCache.get(key); } catch { redisAvailable = false; return lruCache.get(key); } }, // 设置缓存 async set(key: string, value: any, options?: { tags?: string[]; ttl?: number }) { const ttlSec = options?.ttl || 3600; const ttlMs = ttlSec * 1000; try { if (redisAvailable) { await redisClient.set(key, JSON.stringify(value), { EX: ttlSec }); // 维护标签与缓存键的映射,支持revalidateTag if (options?.tags?.length) { for (const tag of options.tags) { await redisClient.sAdd(`tag:${tag}`, key); } } } lruCache.set(key, value, { ttl: ttlMs }); } catch { redisAvailable = false; lruCache.set(key, value, { ttl: ttlMs }); } }, // 删除缓存 async delete(key: string) { try { if (redisAvailable) await redisClient.del(key); lruCache.delete(key); } catch { redisAvailable = false; lruCache.delete(key); } }, // 按标签失效缓存 async revalidateTag(tag: string) { try { if (redisAvailable) { const keys = await redisClient.sMembers(`tag:${tag}`); if (keys.length) { await redisClient.del(...keys); await redisClient.del(`tag:${tag}`); } } // LRU按标签清理:需提前在缓存值中携带tags字段,或维护本地标签映射 for (const [key] of lruCache.entries()) { const cachedValue = lruCache.get(key); if (cachedValue?.tags?.includes(tag)) { lruCache.delete(key); } } } catch { redisAvailable = false; // 同上处理LRU的标签清理 for (const [key] of lruCache.entries()) { const cachedValue = lruCache.get(key); if (cachedValue?.tags?.includes(tag)) { lruCache.delete(key); } } } }, }; export default cacheHandler;
3. 配置Next.js启用自定义处理器
修改next.config.ts,指定缓存处理器路径:
import type { NextConfig } from 'next'; const nextConfig: NextConfig = { experimental: { cacheHandler: './app/cache-handler.ts', }, }; export default nextConfig;
4. 兼容App目录与服务器组件
在App目录的服务器组件中,直接使用Next.js原生缓存API即可,缓存操作会自动路由到Redis或LRU:
// app/page.tsx 服务器组件示例 import { unstable_cache } from 'next/cache'; // 封装带缓存的请求 const fetchCachedData = unstable_cache( async () => { const res = await fetch('https://api.example.com/data', { cache: 'force-cache' }); return res.json(); }, ['data-cache-key'], // 缓存键 { tags: ['data-tag'], ttl: 3600 } // 标签与过期时间 ); export default async function Page() { const data = await fetchCachedData(); return <div>{JSON.stringify(data)}</div>; }
关键注意事项
- Redis容错:通过监听客户端错误事件,自动切换到LRU,避免服务因Redis不可用崩溃。
- LRU配置优化:根据业务场景调整
max(内存占用)和ttl(缓存时效)参数。 - 标签清理性能:如果需要高频使用
revalidateTag,建议在LRU中也维护标签-键的映射表,避免遍历所有缓存条目。 - 类型安全:确保缓存值的JSON序列化/反序列化逻辑正确,避免类型错误。
内容的提问来源于stack exchange,提问作者Besok
相关产品推荐
相关产品推荐

