Подтвердить что ты не робот

Обработка нескольких параллельных HTTP-запросов в Node.js

Я знаю, что 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);
4b9b3361

Ответ 1

Вы не понимаете, как работает node. Вышеприведенный код может принимать TCP-соединения от сотен или тысяч клиентов, читать HTTP-запросы, а затем ждать тайм-аута 4000 мс, который вы испекли там, а затем отправлять ответы. Каждый клиент получит ответ примерно в 4000 + небольшое количество миллисекунд. Во время этого setTimeout (и во время любой операции ввода-вывода) node может продолжить обработку. Это включает в себя прием дополнительных TCP-соединений. Я проверил ваш код, и браузеры получили ответ в 4s. Второй не принимает 8, если это так, как вы думаете, что это работает.

Я запустил curl -s localhost:8080 на 4 вкладках так быстро, как могу, используя клавиатуру, и секунды в метках времени:

  • от 54 до 58
  • от 54 до 58
  • от 55 до 59
  • От 56 до 00

Здесь нет проблем, хотя я могу понять, как вы думаете, что есть один. node будет полностью нарушен, если он будет работать, как предлагалось ваше сообщение.

Здесь еще один способ проверить:

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

Ответ 2

Ваш код может принимать несколько соединений, потому что задание выполняется в функции обратного вызова вызова setTimeout.

Но если вы вместо setTimeout выполняете тяжелую работу... тогда это правда, что node.js не будет принимать другие множественные соединения! SetTimeout случайно освобождает процесс, поэтому node.js может принимать другие задания, а код выполняется в другом "потоке".

Я не знаю, какой правильный способ реализовать это. Но так оно и работает.

Ответ 3

Браузер блокирует другие запросы. Если вы вызовете это из разных браузеров, это будет работать параллельно.

Ответ 4

Я использовал следующий код для проверки обработки запросов

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);
});

Поскольку этот запрос не занимает столько времени обработки, за исключением 50 секунд setTimeout, и весь тайм-аут обрабатывался вместе, как обычно.

Ответ на запрос 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") 

Таким образом, для всех функций Async theres виртуальный поток в Node и Node принимает другой запрос перед выполнением предыдущих запросов async, например, (fs, mysql или call API), однако он сохраняет его как отдельный поток и не обрабатывает другой запрос до тех пор, пока все предыдущие не будут завершены.