在Node.js中处理多个并行的HTTP请求

我知道Node是非阻塞的,但我只是意识到http.listen(8000)的默认行为意味着所有的HTTP请求都是一次处理的。 我知道我不应该对此感到惊讶(这是端口的工作原理),但是它确实让我非常想知道如何编写我的代码,以便处理多个并行的HTTP请求。

那么编写服务器的最好方法是什么,以避免端口80和长时间运行的响应不会导致长时间的请求队列?

为了说明问题,请尝试运行下面的代码,并同时在两个浏览器选项卡中加载它。

 var http = require('http'); http.createServer(function (req, res) { res.setHeader('Content-Type', 'text/html; charset=utf-8'); res.write("<p>" + new Date().toString() + ": starting response"); setTimeout(function () { res.write("<p>" + new Date().toString() + ": completing response and closing connection</p>"); res.end(); }, 4000); }).listen(8080); 

你误解了节点是如何工作的。 上面的代码可以接受来自数百或数千客户端的TCP连接,读取HTTP请求,然后等待您在那里烘烤4000毫秒的超时,然后发送响应。 每个客户端都会在大约4000毫秒的时间内得到一个响应。 在setTimeout期间(以及在任何I / O操作期间),节点可以继续处理。 这包括接受更多的TCP连接。 我testing了你的代码,浏览器每个都得到了4秒的响应。 第二个不需要8s,如果这是你认为它的工作原理。

我通过键盘快速地在4个标签中运行curl -s localhost:8080 ,时间戳中的秒数是:

  1. 54至58
  2. 54至58
  3. 55至59
  4. 56到00

这里没有问题,虽然我可以理解你会怎么想有一个问题。 如果按照您的post所build议的那样工作,那么节点将会完全破坏

这是validation的另一种方法:

 for i in 1 2 3 4 5 6 7 8 9 10; do curl -s localhost:8080 &;done 

您的代码可以接受多个连接,因为该作业是在setTimeout调用的callback函数中完成的。

但是,如果你而不是setTimeout做了一个沉重的工作…那么确实node.js不会接受其他多个连接! SetTimeout意外地释放了进程,所以node.js可以接受其他作业,而你的代码在其他“线程”中执行。

我不知道哪个是实施这个的正确方法。 但这似乎是如何工作的。

浏览器阻止其他相同的请求。 如果你从不同的浏览器调用它,那么这将并行工作。

我使用下面的代码来testing请求处理

 app.get('/', function(req, res) { console.log('time', MOMENT()); setTimeout( function() { console.log(data, ' ', MOMENT()); res.send(data); data = 'changing'; }, 50000); var data = 'change first'; console.log(data); }); 

由于这个请求并没有花费太多的处理时间,除了setTimeout的50秒之外,所有的超时都像平时一样被处理。

共同回应3请求 –

 time moment("2017-05-22T16:47:28.893") change first time moment("2017-05-22T16:47:30.981") change first time moment("2017-05-22T16:47:33.463") change first change first moment("2017-05-22T16:48:18.923") change first moment("2017-05-22T16:48:20.988") change first moment("2017-05-22T16:48:23.466") 

在此之后,我转移到第二阶段…即,如果我的请求需要这么多时间来处理一个同步文件或其他一些事情,需要时间。

 app.get('/second', function(req, res) { console.log(data); if(req.headers.data === '9') { res.status(200); res.send('response from api'); } else { console.log(MOMENT()); for(i = 0; i<9999999999; i++){} console.log('Second MOMENT', MOMENT()); res.status(400); res.send('wrong data'); } var data = 'second test'; }); 

由于我的第一个请求仍在处理中,所以我的第二个请求没有被Node所接受。 因此,我得到了2个请求的响应 –

 undefined moment("2017-05-22T17:43:59.159") Second MOMENT moment("2017-05-22T17:44:40.609") undefined moment("2017-05-22T17:44:40.614") Second MOMENT moment("2017-05-22T17:45:24.643") 

因此,对于所有asynchronous函数,Node和Node中的虚拟线程在完成像(fs,mysql或调用API)之类的asynchronous工作之前接受其他请求,但是它保持它自己作为单个线程并且不处理其他请求,直到所有以前的完成。