Next.js 14应用启动时通过Redis缓存主数据的实现方案
在Next.js 14中启动时预加载主数据到Redis的实现方案
1. 安装Redis客户端依赖
首先安装官方Redis客户端包:
npm install redis
2. 编写数据预加载脚本
在项目根目录创建scripts/preload-redis.js,负责读取主数据并写入Redis:
import { createClient } from 'redis'; // 假设主数据存储在项目的data目录下,可根据实际路径调整 import countries from '../data/countries.json' assert { type: 'json' }; import heights from '../data/heights.json' assert { type: 'json' }; import ages from '../data/ages.json' assert { type: 'json' }; import occupations from '../data/occupations.json' assert { type: 'json' }; async function preloadRedisData() { // 初始化Redis客户端,可通过环境变量配置连接地址 const client = createClient({ url: process.env.REDIS_URL || 'redis://localhost:6379' }); client.on('error', err => console.error('Redis连接失败:', err)); await client.connect(); try { // 将各列表序列化为JSON字符串存入Redis await Promise.all([ client.set('countries', JSON.stringify(countries)), client.set('heights', JSON.stringify(heights)), client.set('ages', JSON.stringify(ages)), client.set('occupations', JSON.stringify(occupations)) ]); console.log('所有主数据已成功预加载至Redis'); } catch (err) { console.error('预加载数据出错:', err); process.exit(1); // 加载失败时终止启动流程 } finally { await client.disconnect(); } } preloadRedisData();
3. 修改启动脚本,实现启动前自动加载
修改package.json中的dev和start脚本,利用npm的pre前缀钩子,在启动Next.js前自动执行预加载脚本:
{ "scripts": { "predev": "node scripts/preload-redis.js", "dev": "next dev", "prestart": "node scripts/preload-redis.js", "start": "next start" } }
npm会自动执行前缀为
pre的脚本,比如执行npm run dev时,会先运行predev,再启动next dev。
4. 封装Redis数据读取工具
创建utils/redis-client.js,封装Redis客户端和数据读取逻辑,避免重复创建连接:
import { createClient } from 'redis'; let redisClient; async function getClient() { if (!redisClient) { redisClient = createClient({ url: process.env.REDIS_URL || 'redis://localhost:6379' }); redisClient.on('error', err => console.error('Redis客户端异常:', err)); await redisClient.connect(); } return redisClient; } export async function getCachedList(key) { const client = await getClient(); const data = await client.get(key); return data ? JSON.parse(data) : null; }
5. 在应用中调用缓存数据
在服务器组件或API路由中直接使用封装好的工具函数获取数据:
import { getCachedList } from '@/utils/redis-client'; export default async function CountriesPage() { const countries = await getCachedList('countries'); if (!countries) { return <div>数据加载失败</div>; } return ( <div> <h2>国家列表</h2> <ul> {countries.map(country => ( <li key={country.id}>{country.name}</li> ))} </ul> </div> ); }
替代方案:首次请求时自动加载
如果不想修改启动脚本,可在App Router的根布局中添加懒加载逻辑——当Redis中无数据时自动写入,首次访问应用时完成预加载:
// app/layout.js import { getClient } from '@/utils/redis-client'; import countries from '../data/countries.json'; import heights from '../data/heights.json'; import ages from '../data/ages.json'; import occupations from '../data/occupations.json'; export default async function RootLayout({ children }) { const client = await getClient(); // 检查是否已有缓存数据 const [hasCountries, hasHeights, hasAges, hasOccupations] = await Promise.all([ client.exists('countries'), client.exists('heights'), client.exists('ages'), client.exists('occupations') ]); if (!hasCountries || !hasHeights || !hasAges || !hasOccupations) { await Promise.all([ client.set('countries', JSON.stringify(countries)), client.set('heights', JSON.stringify(heights)), client.set('ages', JSON.stringify(ages)), client.set('occupations', JSON.stringify(occupations)) ]); console.log('首次访问,预加载数据至Redis'); } return ( <html lang="zh-CN"> <body>{children}</body> </html> ); }
此方案无需修改启动脚本,但数据加载时机为首次请求时,而非应用启动时。
注意事项
- 确保Redis服务已启动,连接地址配置正确(生产环境建议通过环境变量
REDIS_URL配置)。 - 若主数据需要更新,需添加缓存失效机制(如增加版本号键、定时重新加载)。
- 预加载脚本中可添加
process.exit(1)确保数据加载失败时终止应用启动,避免服务启动后无可用数据。
内容的提问来源于stack exchange,提问作者dasunekanayake
相关产品推荐
相关产品推荐

