Node.js应用使用Redis客户端缓存时遭遇ClientClosedError问题求助
解决Redis ClientClosedError: The client is closed错误
问题场景
以下是我Node.js项目index.js中的代码:
const express = require('express'); const axios = require('axios'); const cors = require('cors'); const redis = require('redis'); const port = 3000; const DEFAULT_EXPIRATION = 3600; const redisClient = redis.createClient(); redisClient.on('error', (error) => { console.error('Redis error:', error); }); redisClient.on('connect', () => { console.log('Connected to Redis server'); }); const app = express(); app.use(cors()); app.get("/photos", async (req, res) => { try { const albumId = req.query.albumId; const { data } = await axios.get( "https://jsonplaceholder.typicode.com/photos", { params: { albumId } } ); redisClient.set('photos', JSON.stringify(data)); redisClient.expire('photos', DEFAULT_EXPIRATION); res.json(data); } catch (error) { console.error("Error fetching photos:", error); res.status(500).json({ error: "Failed to fetch photos" }); } }); app.get("/photos/:id", async (req, res) => { try { const photoId = req.params.id; const { data } = await axios.get( `https://jsonplaceholder.typicode.com/photos/${photoId}` ); res.json(data); } catch (error) { console.error("Error fetching photo:", error); res.status(500).json({ error: "Failed to fetch photo" }); } }); app.listen(port, () => { console.log(`Server running on port ${port}`); });
运行时触发如下错误:
return Promise.reject(new errors_1.ClientClosedError()); ^ ClientClosedError: The client is closed
已导入createClient方法,但问题未解决,需要排查并修复。
问题原因及修复方案
原因
Redis v4+版本中,createClient()创建实例后不会自动连接,必须手动调用connect()方法;同时旧版的connect事件监听也不再适用,需要改用ready事件。
修复步骤
手动调用connect()并处理连接逻辑
将Redis客户端的初始化代码修改为异步方式,确保连接成功后再启动Express服务:const redisClient = redis.createClient(); // 替换connect事件为ready事件 redisClient.on('ready', () => { console.log('Connected to Redis server'); // 连接成功后启动服务 app.listen(port, () => { console.log(`Server running on port ${port}`); }); }); redisClient.on('error', (error) => { console.error('Redis error:', error); }); // 手动触发连接 (async () => { try { await redisClient.connect(); } catch (err) { console.error('Failed to connect to Redis:', err); process.exit(1); // 连接失败时退出进程 } })();使用Promise/async-await处理Redis命令
Redis v4+的命令返回Promise,建议改用await确保命令执行成功,避免因客户端未就绪导致的错误:
在/photos接口中修改Redis操作:// 替换原有的set和expire为await方式,直接设置过期时间 await redisClient.set('photos', JSON.stringify(data), { EX: DEFAULT_EXPIRATION });可选:指定Redis连接参数
如果Redis服务不在本地默认端口,需要在createClient中传入配置:const redisClient = redis.createClient({ url: 'redis://localhost:6379' // 根据实际地址修改 });
完整修复后的代码示例
const express = require('express'); const axios = require('axios'); const cors = require('cors'); const redis = require('redis'); const port = 3000; const DEFAULT_EXPIRATION = 3600; const redisClient = redis.createClient(); redisClient.on('ready', () => { console.log('Connected to Redis server'); app.listen(port, () => { console.log(`Server running on port ${port}`); }); }); redisClient.on('error', (error) => { console.error('Redis error:', error); }); (async () => { try { await redisClient.connect(); } catch (err) { console.error('Failed to connect to Redis:', err); process.exit(1); } })(); const app = express(); app.use(cors()); app.get("/photos", async (req, res) => { try { const albumId = req.query.albumId; const { data } = await axios.get( "https://jsonplaceholder.typicode.com/photos", { params: { albumId } } ); await redisClient.set('photos', JSON.stringify(data), { EX: DEFAULT_EXPIRATION }); res.json(data); } catch (error) { console.error("Error fetching photos:", error); res.status(500).json({ error: "Failed to fetch photos" }); } }); app.get("/photos/:id", async (req, res) => { try { const photoId = req.params.id; const { data } = await axios.get( `https://jsonplaceholder.typicode.com/photos/${photoId}` ); res.json(data); } catch (error) { console.error("Error fetching photo:", error); res.status(500).json({ error: "Failed to fetch photo" }); } });
内容的提问来源于stack exchange,提问作者Gokul Srinivas
相关产品推荐
相关产品推荐

