2013-06-06 2 views
29

Я пишу простую конечную точку api, чтобы определить, сможет ли мой сервер добраться до Интернета. Он отлично работает, но после 5 запросов (ровно 5, каждый раз) запрос зависает. То же самое происходит, когда я переключаю Google на Hotmail.com, что заставляет меня думать, что это что-то на моем конце. Нужно ли закрывать запросы http.get? У меня создалось впечатление, что эта функция автоматически закрывает запросы.node.js http.get зависает после 5 запросов к удаленному сайту

// probably a poor assumption, but if Google is unreachable its generally safe to say  that the server can't access the internet 
// using this client side in the dashboard to enable/disable internet resources 

app.get('/api/internetcheck', function(req, res) { 
console.log("trying google..."); 
    http.get("http://www.google.com", function(r){ 
     console.log("Got status code!: " +r.statusCode.toString()); 
     res.send(r.statusCode.toString()); 
     res.end(); 
     console.log("ended!"); 
    }).on('error', function(e) { 
     console.log("Got error: " + e.message); 
    }); 
}); 
+0

, имеющей «res.end()» Похоже, что строка имеет браузер «повиснуть» (т.е. Chrome будет застрял погрузка страница). Удаление приведет к успешному рендерингу кода состояния (независимо от того, сколько раз или как быстро эти запросы были сделаны - я пробовал 100 раз в цикле for, и все прошло хорошо). – funseiki

ответ

50

Вот причина "именно 5": https://nodejs.org/docs/v0.10.36/api/http.html#http_agent_maxsockets

Внутри http модуль использует класс агента для управления HTTP-запросов. Этот агент будет по умолчанию разрешать максимум 5 открытых подключений к одному и тому же HTTP-серверу.

В вашем коде вы не используете фактический ответ, отправленный Google. Таким образом, агент предполагает, что вы не закончили с запросом и не откроете соединение. И поэтому после 5 запросов агент больше не позволит вам создавать новое соединение и начнет ждать завершения любого из существующих подключений.

Очевидным решением было бы просто потреблять данные:

http.get("http://www.google.com", function(r){ 
    r.on('data', function() { /* do nothing */ }); 
    ... 
}); 

Если вы столкнулись с проблемой, что ваш /api/internetcheck маршрут называется много, так что вам нужно, чтобы обеспечить более 5 одновременных соединений, может либо увеличить размер пула соединений, либо полностью отключить агент (хотя вам все равно необходимо будет использовать данные в обоих случаях);

// increase pool size 
http.globalAgent.maxSockets = 100; 

// disable agent 
http.get({ hostname : 'www.google.com', path : '/', agent : false }, ...) 

Или, возможно, использовать HEAD запрос вместо GET.

(PS: в случае, если http.get генерирует ошибку, вы все равно должны завершить ответ HTTP, используя res.end() или что-то в этом роде).

ПРИМЕЧАНИЕ: в версии Node.js> = 0,11, maxSockets устанавливается в Infinity.

+0

отличный ответ, спасибо! – scald

+2

Просто, чтобы добавить к этому отличный ответ - моя проблема была в том, что я загрузил PNG-капли с удаленного сервера, в том случае, когда не было соответствующего блога, я по умолчанию использовал двоичную blob-версию по умолчанию, а не возвращал ошибку 404. Я получил эту проблему, потому что я не потреблял загруженные данные ... очень умно! Так же, как и выше - включить r.on ('data', function() {/ * do nothing * /}); и он обманывает это, думая, что вы делаете и закрываете соединение! – sidonaldson

+0

Возрождение довольно старого поста, но требования к потреблению также применяются к ответам, отличным от 200? Если вы получаете что-то вроде 4xx или 5xx и не используете r.on ('data'), это соединение не закрыто? – Johnny

2

Если вы подождете достаточно долго, 5 запросов будут тайм-аут, а следующие 5 будут обрабатываться, поэтому приложение не будет действительно висит, потому что оно в конечном итоге обработает все запросы.

Чтобы ускорить этот процесс, что вам нужно сделать что-то с ответными данными, такими как r.on('data', function() {});

Смежные вопросы