Redis无法存储数据及Node.js API无响应问题排查求助
Redis Node.js API调用无响应问题排查与解决
问题核心原因
你的代码混合使用Redis回调API与async/await,且错误处理机制失效,导致请求触发异常时无法返回响应,最终一直处于加载状态:
- 回调内抛出的错误无法被外层
try/catch捕获:client.get的回调是异步执行的,外层try/catch管不到这个上下文里的错误,一旦Redis操作出错,代码直接抛出错误但没有返回响应,请求就会挂起。 - async回调的Promise错误未处理:给回调函数加了
async后,内部await操作的错误会变成未处理的Promise拒绝,同样不会触发外层捕获,导致请求无响应。 - 手动处理过期时间冗余且易出错:自己存储
expiration字段判断过期,不仅代码冗余,还可能因为日期解析问题引发隐藏错误。
修复方案
1. 改用Redis客户端的Promise/async/await风格API
最新版redis包原生支持async/await,完全可以抛弃回调,统一用异步语法,让错误能被外层try/catch正常捕获:
import { createClient } from 'redis'; const client = createClient({ url: 'redis://default:mypass@redis-16246.c81.us-east-1-2.ec2.cloud.redislabs.com:16246' }); // 监听Redis连接与错误日志 client.on('error', err => console.log('Redis Client Error', err)); client.on('connect', () => console.log('Redis Client Connected')); // 建议在服务启动时完成Redis连接,避免模块顶层await的潜在问题 (async () => { await client.connect(); })(); router.post("/getuserwithpet", async (req, res) => { try { const { email } = req.body; // 用async/await调用Redis get const cachedData = await client.get(email); if (cachedData) { const cacheObj = JSON.parse(cachedData); const now = new Date(); const expiration = new Date(cacheObj.expiration); if (expiration > now) { return res.json(cacheObj.data); } } // 增加用户不存在的边界判断 const user = await User.findOne({ email }); if (!user) { return res.status(404).json({ error: "用户不存在" }); } const pet = user.pet; const count = await User.countDocuments({ pet }); if (count === 0) { return res.status(404).json({ error: "没有找到饲养该宠物的用户" }); } let dataToCache; if (cachedData) { dataToCache = JSON.parse(cachedData).data; } else { dataToCache = await User.aggregate([ { $match: { pet, email: { $ne: email } } }, { $sample: { size: 1 } }, { $project: { name: 1, username: 1, profileImg: 1 } }, ]); } // 构造缓存数据并存储 const now = new Date(); const expiration = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, Math.floor(Math.random() * 6) + 5, 0, 0, 0); const dataToCacheWithExpiration = { data: dataToCache, expiration }; // 用async/await调用Redis set,确保操作完成 await client.set(email, JSON.stringify(dataToCacheWithExpiration)); res.json(dataToCache); } catch (err) { console.log(err); res.status(500).json({ error: err.message || "服务器内部错误" }); } });
2. 优化缓存过期逻辑(可选)
不需要手动维护过期时间,直接用Redis自带的EX参数设置键的自动过期,代码更简洁可靠:
// 计算过期秒数(明天5-11点过期) const now = new Date(); const expiration = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, Math.floor(Math.random() * 6) + 5, 0, 0, 0); const expireSeconds = Math.floor((expiration.getTime() - now.getTime()) / 1000); // 设置缓存并指定自动过期时间 await client.set(email, JSON.stringify(dataToCache), { EX: expireSeconds }); // 获取时直接判断是否存在即可,Redis会自动删除过期键 const cachedData = await client.get(email); if (cachedData) { return res.json(JSON.parse(cachedData)); }
3. 验证Redis连接有效性
- 检查Redis URL的用户名、密码、主机、端口是否完全正确
- 确认Redis实例的防火墙/安全组允许你的服务器IP访问
- 通过
client.on('connect')日志确认连接成功
内容的提问来源于stack exchange,提问作者user21687269
相关产品推荐
相关产品推荐

