现在的招聘里,往往都有一条:“熟悉 Node.js,有 BFF 开发经验者优先。”
当我们用 Node.js 写接口转发、写 SSR 时,有一个问题绕不开:状态共享。
- 用户登录了:Session 存在哪?存在
global.session 变量里?那服务器重启就没了。
- 接口限流:限制 IP 每分钟访问 60 次。存在
Map 里?那如果你开启了 PM2 多进程,每个进程的数据是不互通的。
这时候,我们需要一个“外挂的大脑”——Redis。它是内存数据库,速度极快(微秒级),且天然支持原子操作。
今天,我们用 Redis + Node.js 解决两个真实痛点:接口限流和分布式 Session。
为什么要用 Redis?(给前端的解释)
你可以把 Node.js 进程想象成一个“收银员”。
- 没有 Redis:收银员把账记在自己的脑子里(内存)。如果换班了(重启),或者开了两个收银台(多进程),账就乱了。
- 有了 Redis:收银员把账写在身后的黑板上(Redis)。不管换几个收银员,大家看的都是同一块黑板。
核心特性:
- 极速:基于内存,读写几十万次/秒。
- 原子性:多个请求同时改一个数据,Redis 能保证排队执行,不会数据错乱。
实战场景 A:接口限流 (Rate Limiting)
需求:限制每个 IP,每 60 秒只能访问接口 10 次。
代码实现 (使用 ioredis 库):
import Redis from 'ioredis';
const redis = new Redis(); // 默认连接本地 6379
async function rateLimitMiddleware(ctx, next) {
const ip = ctx.request.ip;
const key = `limit:${ip}`;
// 1. 获取当前 IP 的访问次数
const current = await redis.get(key);
if (current && current >= 10) {
// 2. 超过限制,直接拒绝
ctx.status = 429;
ctx.body = { msg: '手速太快了,休息一下' };
return;
}
// 3. 计数 +1(原子操作)
// multi() 是事务,保证两条命令一起执行
await redis.multi()
.incr(key) // 自增
.expire(key, 60) // 💡 关键:每次访问都重置/或设置过期时间?
// 👆 这里有个坑:简单的做法是第一次设置过期,后续只 incr
// 更好的做法是用 Lua 脚本保证原子性
.exec();
await next();
}
🔥 进阶:Lua 脚本 (面试杀手锏)
上面的代码在高并发下有漏洞(比如 incr 和 expire 之间断网了)。
最完美的写法是用 Lua 脚本 将判断逻辑打包发给 Redis:
-- limit.lua
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('get', key) or "0")
if current + 1 > limit then
return 0 -- 拒绝
else
redis.call("INCRby", key, 1)
redis.call("expire", key, 60)
return 1 -- 通过
end
实战场景 B:分布式 Session
痛点:Token 无状态(JWT)虽然好,但无法“强制踢人下线”。
如果我想实现“修改密码后,所有设备强制登出”,JWT 做不到(除非换 Secret)。
解法:Redis 存 Session/Token 黑名单
// 登录成功
async function login(user) {
const token = generateUUID();
// 存入 Redis,30分钟过期
// Key: session:token123 Value: userId
await redis.set(`session:${token}`, user.id, 'EX', 1800);
return token;
}
// 中间件校验
async function authMiddleware(ctx, next) {
const token = ctx.headers['authorization'];
// 去 Redis 查这张“票”还有效吗
const userId = await redis.get(`session:${token}`);
if (!userId) {
ctx.status = 401;
return;
}
// 续期 (活跃用户自动续时间)
await redis.expire(`session:${token}`, 1800);
ctx.user = { id: userId };
await next();
}
优势:只要我在 Redis 里删掉这个 Key,用户下一秒请求就会 401,立刻下线。
2026 前端架构趋势:Serverless Redis
面试官可能会问:“前端不会运维,Redis 谁来管?”
在 2026 年,我们通常使用 Upstash 或 Vercel KV 这种 Serverless Redis。
你不需要买服务器装 Redis,直接调 API 就能用,按量付费。这才是前端全栈的未来。
结语
Redis 是后端领域的“瑞士军刀”。
对于前端工程师来说,不需要精通 Redis 的持久化原理(RDB/AOF),但必须掌握它的数据结构(String, Hash, List)和应用场景(缓存、限流、消息队列)。
当你开始思考“数据存在哪最安全/最快”时,你就已经脱离了单纯的 UI 开发,迈向了全栈架构。想获取更多实战经验和前沿架构知识,欢迎来 云栈社区 交流探讨。