如何实现NodeJs防重复提交?

阅读 11k
2 个回答

最简单的方法是在客户端那边去做限制,在最后一个请求没响应回来之前不能发起另外的请求。

服务端这边方法也有很多,

  1. 最简单在数据库层面防止重复数据写入

  2. 使用一些 RateLimit 定义规定时间内同一操作不能超过多少次,如果你用的是 Express 可以用这个 https://github.com/nfriedly/express-rate-limit

  3. 正如你提到的采用队列写入

  4. 每次提交都需要申请一个 token ,每个 token 只能用一次

@KaiChen :3Q 4 U answer ~~

我用express-rate-limit实现了一下,

在不改写这个module(以下简称rl)的前提下,会有几个问题:

  1. 首先,看源码,rl将req.ip存放在一个全局变量中,当使用nginx做反向代理的时候,所有的req.ip会指向nginx的代理ip地址,所以这个rl在生产上应该会变现出ip重复问题
  2. 其次,max限制次数的逻辑问题,当设置max大于1之后,次数越多,请求的延迟时间越长,找到一个解决方法是设置【delayMs:0】
  3. 最主要的,他的返回message只支持string型,“first argument must be a string or Buffer”,在res的返回中,我们绝大部分使用的是res.json,纯string数据需要使用正则去进行匹配来判断是否是成功请求。

2019年04月01日21:05:17更新

/**
 * 使用 redis-set 来限制仅允许1次频率的访问
 * @param {string} key 唯一标记
 * @param {number} expire 过期时间(单位s)
 * @param {string} msg 错误信息
 */
function rateLimitRequestByKey(key, expire, msg = '请求频率过快') {
  const member = 'rateLimit'; // set-member键
  const setKey = `${member}:${key}`; // set-key键
  return new Promise((resolve, reject) => {
    redisClient
      .multi() // 开启事务
      .sadd(setKey, member)
      .expire(setKey, expire)
      .exec((err, reply) => {
        if (err) { reject(err); }
        if (reply && reply.length === 2 && reply[0] === 0) {
          const error = new Error(msg);
          error.name = 'RateLimitRequestError';
          reject(error);
        }
        return resolve(reply);
      });
  });
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题