You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 12:49:34