You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 17:58:15