Express+React项目中Redis操作刷新令牌时触发TypeError: Invalid argument type错误求助
Express+React项目中Redis操作刷新令牌时触发TypeError: Invalid argument type错误求助
看起来你在实现刷新令牌存储到Redis的逻辑时遇到了类型错误,我帮你梳理下问题根源和解决办法:
问题定位
从错误栈可以看到,错误触发在generateRefreshToken函数的redisClient.set(userId, refreshToken)这一行,具体是@redis/client库的编码器抛出的类型错误——这个库对传入命令的参数类型有严格要求,键和值必须是字符串(或Buffer)类型,如果你的userId是数字类型(比如从数据库查询返回的用户ID是Number类型),直接传入就会触发这个错误。
另外还有一个隐藏问题:你的verifyRefreshToken是异步函数,但在/reissue路由里调用时没有加await,这会导致你解构出来的userId和isReissue其实是Promise对象,而非实际值,后续逻辑也会出错。
解决方案
1. 确保Redis操作的参数为字符串类型
修改generateRefreshToken和verifyRefreshToken中的Redis调用,把userId转为字符串:
export const generateRefreshToken = (userId) => { const refreshToken = jwt.sign({ userId }, process.env.JWT_SECRET, { expiresIn: "5m", }); // 将userId转为字符串后存入Redis redisClient.set(userId.toString(), refreshToken); return refreshToken; };
export const verifyRefreshToken = async (token) => { try { const { userId } = jwt.verify(token, process.env.JWT_SECRET); // 同样转换userId为字符串再查询 const data = await redisClient.get(userId.toString()); console.log(data); if (token === data) { return { userId, isReissue: true }; } else { return { userId: null, isReissue: false }; } } catch (err) { console.log(err); // 统一返回格式,避免后续解构出错 return { userId: null, isReissue: false }; } };
2. 修复异步函数调用缺失await的问题
在/reissue路由中,调用verifyRefreshToken时必须加await,否则无法获取到正确的返回值:
router.get("/reissue", async (req, res, next) => { try { if ( !req.headers["authorization"] || !req.headers["authorization"].startsWith("Bearer") ) { return res.status(403).send("유효하지 않습니다"); } const token = req.headers["authorization"].substring(7); // 加上await,等待异步函数执行完成 const { userId, isReissue } = await verifyRefreshToken(token); console.log(userId); console.log(isReissue); // 增加userId非空判断,避免无效查询 if (isReissue && userId) { const user = await User.findOne({ where: { id: userId } }); const userWithoutPwd = user.dataValues; delete userWithoutPwd.password; const newAccessToken = generateAccessToken(userWithoutPwd); const newRefreshToken = generateRefreshToken(userId); return res.status(200).json({ newAccessToken, newRefreshToken }); } else { return res.status(403).send("리프레시 토큰이 유효하지 않습니다"); } } catch (err) { console.log(err); return res.status(500).send("서버 내부 오류"); } });
补充说明
新版的@redis/client库相比旧版redis库,参数类型检查更严格,不会自动帮你转换数字到字符串,所以必须手动处理类型转换。另外异步函数的调用一定要记得加await,否则会拿到Promise对象而非实际返回值,这也是Node.js异步编程中很容易踩的坑。
备注:内容来源于stack exchange,提问作者Sang
相关产品推荐
相关产品推荐

