Javascript 在expressjs中,如何限制可以同时发出请求的用户数量?

Javascript 在expressjs中,如何限制可以同时发出请求的用户数量?,javascript,node.js,express,Javascript,Node.js,Express,我的代码只是一个普通的应用程序: app .use(sassMiddleware({ src: __dirname + '/sass', dest: __dirname + '/', // This line controls sass log output debug: false, outputStyle: 'compressed' })) // More libraries ... .get('/', au

我的代码只是一个普通的应用程序:

app
  .use(sassMiddleware({
      src: __dirname + '/sass',
      dest: __dirname + '/',
      // This line controls sass log output
      debug: false,
      outputStyle: 'compressed'
  }))

  // More libraries
  ...

  .get('/', auth.protected, function (req, res) {
    res.sendfile(__dirname + '/views/index.html');
  })

.post('/dostuff', auth.protected, function (req, res) {
    console.log(req.body)
    res.redirect('back')

    child = require('child_process').spawn(
        './script.rb',
        ['arguments'],
        { stdio: ['ignore', 'pipe', 'pipe'] }
    );
    child.stdout.pipe(process.stdout);
    child.stderr.pipe(process.stdout);
  })
我最初的目标是将/dostuff可以生成的生成数量限制为单个实例。我在想,也许有一种简单的方法可以限制整个应用程序的用户数量,但似乎找不到

我试图寻找一些会话限制机制,但也找不到,只有各种各样的速率限制,但我不认为这是我想要的

由于应用程序在docker中运行,我使用iptalbes限制端口上的tcp连接数,但这已被证明不太理想,因为应用程序在
已建立
状态下保留一些连接,从而防止从一个用户到另一个用户的有效切换

所以。。。有什么程序化的方法吗

更新

该应用程序不是api服务器
/dostuff
实际上是由用户从网页触发的。这就是为什么简单的利率限制不是最好的选择。ruby脚本的执行时间也是可变的

回答

根据@jfriend00给出的以下答案,通过修复我发现的几个逻辑错误:

  .post('/dostuff*', auth.protected, function (req, res) {
    console.log(req.body)

    if (spawnCntr >= spawnLimit)  {
        res.status(502).send('Server is temporarily busy');
        console.log("You already have process running. Please either abort the current run or wait until it completes".red)
        return;
    }

    let childClosed = false
    function done () {
        if (!childClosed) {
          --spawnCntr;
          childClosed = true;
        }
    }

    ++spawnCntr;

    child = require('child_process').spawn(
        blahblah
    );

    child.on('close', done);
    child.on('error', done);
    child.on('exit', done);

    child.stdout.pipe(process.stdout);
    child.stderr.pipe(process.stdout);

    res.redirect('back');
  })

我仍然会接受他的回答,尽管这对我帮助很大

您可以使用node package Express Rate Limit-

对于仅API的服务器,速率限制器应应用于所有请求:

var RateLimit = require('express-rate-limit');

app.enable('trust proxy'); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc) 

var limiter = new RateLimit({
  windowMs: 15*60*1000, // 15 minutes 
  max: 100, // limit each IP to 100 requests per windowMs 
  delayMs: 0 // disable delaying - full speed until the max limit is reached 
});

//  apply to all requests 
app.use(limiter);
var RateLimit = require('express-rate-limit');

app.enable('trust proxy'); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc) 

var apiLimiter = new RateLimit({
  windowMs: 15*60*1000, // 15 minutes 
  max: 100,
  delayMs: 0 // disabled 
});

// only apply to requests that begin with /api/ 
app.use('/api/', apiLimiter);
对于“常规”web服务器(例如,任何使用express.static()的服务器),速率限制器应仅适用于某些请求:

var RateLimit = require('express-rate-limit');

app.enable('trust proxy'); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc) 

var limiter = new RateLimit({
  windowMs: 15*60*1000, // 15 minutes 
  max: 100, // limit each IP to 100 requests per windowMs 
  delayMs: 0 // disable delaying - full speed until the max limit is reached 
});

//  apply to all requests 
app.use(limiter);
var RateLimit = require('express-rate-limit');

app.enable('trust proxy'); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc) 

var apiLimiter = new RateLimit({
  windowMs: 15*60*1000, // 15 minutes 
  max: 100,
  delayMs: 0 // disabled 
});

// only apply to requests that begin with /api/ 
app.use('/api/', apiLimiter);

您可以保留一个简单的计数器,显示同时有多少
spawn()
操作在进行中,如果新请求进来,并且您当前超过该限制,您只需返回一个502错误(服务器暂时繁忙)


注意:您问题中的代码没有将
child
声明为一个局部变量,看起来像是一个等待发生的bug。

我的答案有用吗?或者您还需要什么吗?@DamienGold更新了我的答案,解释了为什么我认为在这种情况下利率限制会很笨拙。我更新了我的答案。第二种选择应该适合你。如果是的话,把它标记为解决方案。这看起来不像是一个利率限制问题。生成的进程运行的时间不确定,因此无法使用定时速率限制器一次仅管理一个生成的进程,而不大量夸大时间限制,从而使您甚至无法执行一个请求,并且在请求完成时执行另一个请求。这根本不是一个速率限制问题,就连OP也已经说过。我之所以不将child声明为函数变量,是因为我需要能够从另一个
.get
请求终止它。@user3081519-那么
spawnLimit
必须是
1
,因为如果它是任何其他值,然后,在生成第二个变量时,您将覆盖
子变量。