Node.js中Redis连接复用方案:工具函数还是中间件?
Redis连接复用:工具函数是更适合你的方案
你当前的问题是每次请求都重复创建Redis连接,既冗余又会导致过多连接占用资源。工具函数和中间件都能解决这个问题,但工具函数更简单直接,完全匹配你的需求。
一、工具函数方案(推荐)
创建一个独立的Redis客户端工具文件,全局复用同一个连接实例,所有控制器直接导入使用即可。
步骤1:创建Redis工具文件
在项目的utils/redisClient.js中编写如下代码:
const redis = require('redis'); // 初始化Redis客户端 const client = redis.createClient('redis://127.0.0.1:6379'); // 监听连接错误 client.on('error', (err) => { console.error('Redis连接异常:', err); }); // 提前完成连接(v4+版本支持自动重连,无需担心断开问题) (async () => { await client.connect(); })(); module.exports = client;
步骤2:修改控制器代码
删掉原来重复的Redis连接代码,直接导入工具文件中的客户端实例:
const asyncHandler = require('../middleware/async'); const Profile = require('../models/Profile.model'); const ErrorResponse = require('../utils/errorResponse'); // 导入全局Redis客户端 const redisClient = require('../utils/redisClient'); //@desc Create a Profile //@route POST /api/profile //@access Private exports.createProfile = asyncHandler(async (req, res, next) => { // 直接复用已连接的客户端 const cached = await redisClient.get('profiles'); const { biography, profileImageUrl, location, birthdate } = req.body; const profileFields = { user_id: req.user.id, biography, location, birthdate, profileImageUrl }; let profile = await Profile.findOne({ where: { user_id: req.user.id } }); if (profile) { // 修正Sequelize的update语法:直接传入更新字段 profile = await profile.update(profileFields, { new: true }); } else { // 补充else逻辑,避免重复创建数据 profile = await Profile.create(profileFields); } // 清除缓存,确保下次请求获取最新数据 await redisClient.del('profiles'); res.status(200).json(profile); }); //@desc Get all Profiles //@route GET /api/profile //@access Public exports.getProfiles = asyncHandler(async (req, res, next) => { const cached = await redisClient.get('profiles'); if(cached) { console.log('Profiles cached'); return res.status(200).json(JSON.parse(cached)); } const profiles = await Profile.findAll(); console.log('Profiles not cached'); // 先写入缓存再返回响应,避免res.send后代码终止执行 await redisClient.SETEX('profiles', 3600, JSON.stringify(profiles)); res.status(200).json(profiles); });
二、中间件方案(可选)
如果需要将Redis客户端与请求上下文绑定(比如根据请求参数切换连接),可以用中间件将客户端挂载到req对象上,但这个方案对你当前需求来说略显冗余。
步骤1:创建Redis中间件
在middleware/redis.js中编写:
const redis = require('redis'); const client = redis.createClient('redis://127.0.0.1:6379'); client.on('error', (err) => console.error('Redis错误:', err)); (async () => { await client.connect(); })(); // 中间件:将客户端挂载到req对象 const redisMiddleware = (req, res, next) => { req.redisClient = client; next(); }; module.exports = redisMiddleware;
步骤2:在路由中挂载中间件
在routes/profile.js中为需要Redis的路由添加中间件:
const express = require('express'); const router = express.Router(); const redisMiddleware = require('../middleware/redis'); const profileController = require('../controllers/profile'); router.post('/', redisMiddleware, profileController.createProfile); router.get('/', redisMiddleware, profileController.getProfiles); module.exports = router;
步骤3:控制器中使用req上的客户端
控制器里直接调用req.redisClient即可:
// createProfile中 const cached = await req.redisClient.get('profiles'); await req.redisClient.del('profiles'); // getProfiles中 const cached = await req.redisClient.get('profiles'); await req.redisClient.SETEX('profiles', 3600, JSON.stringify(profiles));
方案对比
- 工具函数:代码简洁,全局复用单一连接实例,维护成本低,是你当前场景的最优解。
- 中间件:适合需要与请求上下文深度绑定的复杂场景,比如动态切换Redis实例,但会增加不必要的代码层级,对你来说没必要。
内容的提问来源于stack exchange,提问作者tukitooo1998
相关产品推荐
相关产品推荐

