【问题标题】:Node.JS: Best way to handle max requests per minute to a serverNode.JS:处理服务器每分钟最大请求数的最佳方式
【发布时间】:2018-01-14 03:10:36
【问题描述】:

如果这个问题已经得到解答,我很抱歉,我希望我没有违反任何 SO 规则,如果是这样,我提前道歉...... 我想知道处理请求限制器的最佳方法是什么?我在网上看到了一堆油门和速率限制器,但我不确定它如何或是否适用于我的情况。

我正在做一堆基于数组的 [OUTGOING] 请求承诺,而在服务器上我每分钟只能发出 90 个请求。我的请求承诺是由这个命令生成的:return Promise.all(array.map(request))

我想这样处理它:

var i = 0;

return rp({
        url: uri,
        json: true,
      }).then((data) => {
        if (i <=90) {
          i ++;
          return data;
        } else {
          return i;
        }
      });

但我不确定这是否是一种真正有效的处理方式,另外,我还不确定如何处理时间关系...:S

在此先感谢您的帮助,很抱歉我还是个初学者...

【问题讨论】:

  • 您是否尝试限制传出请求或传入请求的数量?
  • 嗨,马特!传出。服务器基本上每分钟只接受90个请求。
  • 在客户端限制请求可能是不可能的,因为如果您达到 90 个请求,用户只需刷新页面并再次发送请求。
  • 话虽如此,您所拥有的似乎是一个解决方案(假设用户不是不断刷新页面),但您应该添加一个 60 秒计时器,将计数重置为零.否则,无论经过多长时间,您都只能发送 90 个请求。
  • 好的。但在这种情况下,我是唯一的客户。目的是限制我的应用程序单独运行(不会被其他任何人在外部使用)。

标签: javascript node.js api request limit


【解决方案1】:

如果请求是从不同的代码部分开始的,那么实现类似于 服务器队列 的方法可能会很有用,它会等待请求直到允许这样做。通用处理程序:

var fromUrl = new Map();

function Server(url, maxPerMinute){
 if(fromUrl.has(url)) return fromUrl.get(url);
 fromUrl.set(url,this);

  this.tld = url;
  this.maxPerMinute = maxPerMinute;
  this.queue = [];
  this.running = false;

}


  Server.prototype ={
   run(d){
    if(this.running && !d) return;
    var curr = this.queue.shift();
    if(!curr){
      this.running = false;
      return;
    }
   var [url,resolve] = curr;
   Promise.all([
     request(this.tld + url),
     new Promise(res => setTimeout(res, 1000*60/this.maxPerMinute)
    ]).then(([res]) => {
       resolve(res);
       this.run(true);
    });
  },
  request(url){
   return new Promise(res => {
      this.queue.push([url,res]);
      this.run();
    });
  }
};

module.exports = Server;

可以这样使用:

 var google = new require("server")("http://google.com");

google.maxPerMinute = 90;

google.request("/api/v3/hidden/service").then(res => ...);

【讨论】:

  • 嗨乔纳斯!再次感谢一百万的持续跟进。在过去的几天里,我很难进入我的项目。我必须承认你的答案正是我正在寻找的,但我担心这对我来说太复杂了......或者换句话说,我对如何在我的内部实现您的代码。我需要深入了解它的每一个部分才能正确理解它,这需要我一段时间......如果你有更多关于这方面的文献,我将不胜感激!
  • @ardzii 好吧,我唯一可以推荐的就是 MDN 文档,上面的代码完全是自己思考的,所以它没有使用任何常见的模式。
  • 嘿嘿嘿!这正是我现在所处的位置......不过,该代码中有很多我不知道的东西,这很令人困惑!但我最终会得到它!我可能会回到这里进行一些澄清 - 可能会一路走来......:S再次感谢您的巨大帮助!
【解决方案2】:

可能每分钟只执行 90 个请求。您可以使用伪递归承诺利用函数:

function multiRequest(urls, maxPerMinute){
 return new Promise(function(cb){
   var result = [];
   //iterate recursively
   (function next(i){
     //if finished resolve promise
     if(i>=urls.length) return cb(result);
      //get all requests
      var requests = Promise.all(urls.slice(i,i+maxPerMinute).map(request));

      //if the requests are done, add them to result
      requests.then(data=>result.push(...data));        

      //if the requests + one minute done, conginue with next
      Promise.all([
        requests,
        new Promise(res=>setTimeout(res,1000*60))    
      ] ).then(_=>next(i+maxPerMinute))
 })(0);
 });
}

像这样使用它:

 multiRequests(["google.com","stackoverflow.com"],90)
  .then(([google,so])=>...);

【讨论】:

  • 嗨乔纳斯!感谢您的回答。我不确定我是否完全理解它......对不起,这绝对是因为我缺乏知识。 Matt 的解决方案似乎对我的代码中的 Promise.all 模块有效...如果您对您的解决方案有更多的了解,那将非常受欢迎!我将阅读更多关于 promise.all ...
  • @ardzii 这些请求返回什么?您需要收集数据吗?
  • 这实际上正是我正在做的事情:我从 3 个不同的服务器获取不同的信息。之后的目标是处理一些信息并将其存储在数据库中。
  • @ardzii 是的,你说得对。 cb 在那里解决迭代结束时的承诺。是的,他每分钟只有 maxPerMinute 个请求,我认为这就是你想要的。
  • @ardzii 是的,舒尔。您可以根据需要随时调用 multiRequest,每个限制仅限制传递的请求。
【解决方案3】:

您可以使用setInterval。查看文档here

var requestCount = 0;

setInterval(function(){
    // Every 60 seconds, reset the count
    requestCount = 0;
}, 60000);

// There needs to be an additional check before calling rp,
// that checks for requestCount > 90, and returns before starting the request.

rp({
    url: uri,
    json: true,
})
.then((data) => {
    requestCount++;
    return data;
});

【讨论】:

  • 这没有意义。它不会阻止发出请求。
  • 是的,请求代码并没有明确地阻止请求的产生,但我假设它会成为其他东西的一部分? OP不清楚。我主要是想用 setInterval 来展示
猜你喜欢
  • 2018-02-13
  • 1970-01-01
  • 1970-01-01
  • 2016-07-10
  • 1970-01-01
  • 2019-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多