Docker中Node.js连接Redis报"Error: The client is closed"问题求助
Docker中Node.js连接Redis出现"Error: The client is closed"的解决方法
问题背景
在Docker环境中部署Node.js服务和Redis服务时,Node.js代码执行时抛出Error: The client is closed错误,相关配置与代码如下:
docker-compose.yml配置
version : "3" services: irbredis: image: redis:7.2.2-alpine container_name: irbredis irbserver: image: node:20.9.0-alpine container_name: irbserver depends_on: - irbredis
Node.js相关代码
redisFunc.js:
const redis = require('redis'); const rclient = redis.createClient({ url: "redis://irbredis:6379" }); module.exports = { rclient : rclient }
sessionMW.js:
const session = require('express-session'); const RedisStore = require('connect-redis').default; module.exports = session({ store: new RedisStore({ client : require('./redisFunc.js').rclient }), //...其他session配置 });
index.js:
const express = require('express'); const app = express(); app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.use(require('./sessionMW.js')); //...其他路由配置
依赖版本
"connect-redis": "^7.1.0", "express": "^4.18.2", "express-session": "^1.17.3", "redis": "^4.6.10",
错误日志
irbserver | Error: The client is closed irbserver | at Commander._RedisClient_sendCommand (/app/node_modules/@redis/client/dist/lib/client/index.js:494:31) irbserver | at Commander.commandsExecutor (/app/node_modules/@redis/client/dist/lib/client/index.js:189:154) irbserver | at BaseClass.<computed> [as get] (/app/node_modules/@redis/client/dist/lib/commander.js:8:29) irbserver | at Object.get (/app/node_modules/connect-redis/dist/cjs/index.js:20:34) irbserver | at RedisStore.get (/app/node_modules/connect-redis/dist/cjs/index.js:53:42) irbserver | at session (/app/node_modules/express-session/index.js:485:11) irbserver | at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) irbserver | at trim_prefix (/app/node_modules/express/lib/router/index.js:328:13) irbserver | at /app/node_modules/express/lib/router/index.js:286:9 irbserver | at Function.process_params (/app/node_modules/express/lib/router/index.js:346:12)
问题原因及解决方法
1. Redis客户端未完成连接就被使用
Redis v4.x版本中,createClient仅创建客户端实例,不会自动建立连接。你的代码直接将未连接的客户端传给connect-redis,导致调用命令时客户端处于关闭状态。
解决方法:
在redisFunc.js中添加连接逻辑,确保连接成功后再导出客户端:
const redis = require('redis'); const rclient = redis.createClient({ url: "redis://irbredis:6379" }); // 监听连接错误 rclient.on('error', (err) => console.error('Redis连接错误:', err)); // 主动建立连接 (async () => { await rclient.connect(); })(); module.exports = { rclient: rclient };
也可以在应用启动前确保连接完成,修改index.js:
const express = require('express'); const app = express(); const redisClient = require('./redisFunc.js').rclient; // 等待Redis连接成功后启动服务 (async () => { await redisClient.connect(); app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.use(require('./sessionMW.js')); app.listen(3000, () => { console.log('服务已启动'); }); })();
2. depends_on仅保证容器启动顺序,不保证Redis服务就绪
docker-compose中的depends_on仅控制容器启动顺序,Redis容器启动后需要时间完成服务初始化,此时Node.js服务可能已尝试连接,导致连接失败。
解决方法:
- 方法一:利用Redis客户端自动重连特性,同时监听
connect事件确认连接状态。 - 方法二:在
docker-compose.yml中添加healthcheck,仅当Redis服务就绪后再启动Node.js容器:
version : "3" services: irbredis: image: redis:7.2.2-alpine container_name: irbredis healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 2s timeout: 2s retries: 5 irbserver: image: node:20.9.0-alpine container_name: irbserver depends_on: irbredis: condition: service_healthy
3. 确认版本兼容性
你的connect-redis@7.1.0与redis@4.6.10版本兼容,后续升级时需注意对应版本匹配,避免兼容性问题。
总结
核心问题是Redis客户端未建立连接就被使用,加上Docker容器启动顺序不代表服务就绪,按上述步骤修改代码和配置即可解决问题。
内容的提问来源于stack exchange,提问作者Robert C. Holland
相关产品推荐
相关产品推荐

