NodeJS - Что на самом деле означает «зависание сокета»?

node.js

303773 просмотра

19 ответа

8160 Репутация автора

Я создаю веб-скребок с Node и Cheerio, и для определенного веб-сайта я получаю следующую ошибку (это происходит только на этом одном веб-сайте, а не на других, которые я пытаюсь очистить).

Это происходит каждый раз в другом месте, поэтому иногда url xвозникает ошибка, в других случаях url xэто нормально, и это совершенно другой URL:

    Error!: Error: socket hang up using [insert random URL, it's different every time]

Error: socket hang up
    at createHangUpError (http.js:1445:15)
    at Socket.socketOnEnd [as onend] (http.js:1541:23)
    at Socket.g (events.js:175:14)
    at Socket.EventEmitter.emit (events.js:117:20)
    at _stream_readable.js:910:16
    at process._tickCallback (node.js:415:13)

Это очень сложно отлаживать, я не знаю, с чего начать. Для того, чтобы начать то , что IS сокет вешает ошибку? Это ошибка 404 или подобное? Или это просто означает, что сервер отказал в соединении?

Я не могу найти объяснение этому нигде!

РЕДАКТИРОВАТЬ: Вот пример кода, который (иногда) возвращает ошибки:

function scrapeNexts(url, oncomplete) {
    request(url, function(err, resp, body) {

        if (err) {
            console.log("Uh-oh, ScrapeNexts Error!: " + err + " using " + url);
            errors.nexts.push(url);
        }
        $ = cheerio.load(body);
        // do stuff with the '$' cheerio content here
    });
}

Прямого вызова для закрытия соединения нет, но я использую, Node Requestкоторый (насколько я могу судить) использует, http.getтак что это не требуется, поправьте меня, если я ошибаюсь!

РЕДАКТИРОВАТЬ 2: Вот фактический, используемый бит кода, который вызывает ошибки. prodURLи другие переменные в основном являются селекторами jquery, которые определены ранее. Это использует asyncбиблиотеку для узла.

function scrapeNexts(url, oncomplete) {
    request(url, function (err, resp, body) {

        if (err) {
            console.log("Uh-oh, ScrapeNexts Error!: " + err + " using " + url);
            errors.nexts.push(url);
        }
        async.series([
                function (callback) {
                    $ = cheerio.load(body);
                    callback();
                },
                function (callback) {
                    $(prodURL).each(function () {
                        var theHref = $(this).attr('href');
                        urls.push(baseURL + theHref);
                    });
                    var next = $(next_select).first().attr('href');
                    oncomplete(next);
                }
            ]);
    });
}
Автор: JVG Источник Размещён: 08.06.2013 01:45

Ответы (19)


48 плюса

223897 Репутация автора

Посмотрите на источник :

function socketCloseListener() {
  var socket = this;
  var parser = socket.parser;
  var req = socket._httpMessage;
  debug('HTTP socket close');
  req.emit('close');
  if (req.res && req.res.readable) {
    // Socket closed before we emitted 'end' below.
    req.res.emit('aborted');
    var res = req.res;
    res.on('end', function() {
      res.emit('close');
    });
    res.push(null);
  } else if (!req.res && !req._hadError) {
    // This socket error fired before we started to
    // receive a response. The error needs to
    // fire on the request.
    req.emit('error', createHangUpError());
    req._hadError = true;
  }
}

Сообщение отправляется, когда сервер никогда не отправляет ответ.

Автор: Blender Размещён: 08.06.2013 01:51

15 плюса

1005 Репутация автора

Продолжая ответ Blender, это происходит в ряде ситуаций. Наиболее распространенные из них, с которыми я сталкиваюсь:

  1. Сервер разбился.
  2. Сервер отклонил ваше соединение, скорее всего, заблокирован User-Agent.

socketCloseListenerКак указано в ответе Блендера, это не единственное место, где создаются ошибки зависания.

Например, нашел здесь :

function socketOnEnd() {
  var socket = this;
  var req = this._httpMessage;
  var parser = this.parser;

  if (!req.res) {
    // If we don't have a response then we know that the socket
    // ended prematurely and we need to emit an error on the request.
    req.emit('error', createHangUpError());
    req._hadError = true;
  }
  if (parser) {
    parser.finish();
    freeParser(parser, req);
  }
  socket.destroy();
}

Вы можете попробовать curlс заголовками и тому подобным, которые отправляются с узла, и посмотреть, получите ли вы ответ там. Если вы не получили ответ curl, но получили ответ в браузере, User-Agentскорее всего , ваш заголовок заблокирован.

Автор: Sly Размещён: 08.06.2013 03:41

43 плюса

1012 Репутация автора

Стоит упомянуть один случай: при подключении из Node.js к Node.js с помощью Express я получаю «зависание сокета», если я не префикс запрошенного пути URL с помощью «/».

Автор: silentorb Размещён: 13.05.2014 05:08

139 плюса

6026 Репутация автора

Есть два случая, когда socket hang upбросают:

Когда вы клиент

Когда вы, как клиент, отправляете запрос на удаленный сервер и не получаете своевременного ответа. Ваш сокет закончен, который выдает эту ошибку. Вам нужно перехватить эту ошибку и решить, как ее обработать: повторить ли запрос, поставить его в очередь на потом и т. Д.

Когда вы сервер / прокси

Когда вы, как сервер, возможно, прокси-сервер, получаете запрос от клиента, затем начинаете действовать на него (или передаете запрос на вышестоящий сервер), и, прежде чем вы подготовите ответ, клиент решает отменить / прервать запрос.

Эта трассировка стека показывает, что происходит, когда клиент отменяет запрос.

Trace: { [Error: socket hang up] code: 'ECONNRESET' }
    at ClientRequest.proxyError (your_server_code_error_handler.js:137:15)
    at ClientRequest.emit (events.js:117:20)
    at Socket.socketCloseListener (http.js:1526:9)
    at Socket.emit (events.js:95:17)
    at TCP.close (net.js:465:12)

Линия http.js:1526:9указывает на то же самое, socketCloseListenerупомянутое выше @Blender, в частности:

// This socket error fired before we started to
// receive a response. The error needs to
// fire on the request.
req.emit('error', createHangUpError());

...

function createHangUpError() {
  var error = new Error('socket hang up');
  error.code = 'ECONNRESET';
  return error;
}

Это типичный случай, если клиент является пользователем в браузере. Запрос на загрузку какого-либо ресурса / страницы занимает много времени, и пользователи просто обновляют страницу. Такое действие приводит к прерыванию предыдущего запроса, который на вашей стороне сервера выдает эту ошибку.

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

console.log(res.socket.destroyed); //true

Таким образом, нет смысла отправлять что-либо, кроме явного закрытия объекта ответа:

res.end();

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

Автор: Eye Размещён: 08.01.2015 07:37

6 плюса

740 Репутация автора

У меня была такая же проблема при использовании библиотеки Nano для подключения к Couch DB . Я попытался настроить пул соединений с помощью библиотеки keepaliveagent, и она продолжала давать сбой с сообщением о зависании сокета .

var KeepAliveAgent = require('agentkeepalive');

var myagent = new KeepAliveAgent({
    maxSockets: 10,
    maxKeepAliveRequests: 0,
    maxKeepAliveTime: 240000
});

nano = new Nano({
    url : uri,
    requestDefaults : {
        agent : myagent
    }
});

После некоторой борьбы я смог прибить проблему - как оказалось, это была очень простая ошибка. Я подключался к базе данных по протоколу HTTPS, но я продолжал передавать своему нано-объекту агент активности активности, созданный в качестве примеров использования этой библиотеки (они полагаются на некоторые значения по умолчанию, использующие http).

Одно простое изменение в использовании HttpsAgent сделало свое дело:

var KeepAliveAgent = require('agentkeepalive').HttpsAgent;
Автор: Marcin T.P. Łuczyński Размещён: 20.03.2015 09:34

7 плюса

2491 Репутация автора

Другой случай, о котором стоит упомянуть (для Linux и OS X), это то, что если вы используете библиотеку, например, httpsдля выполнения запросов, или если вы передаете https://...в качестве URL-адреса локально обслуживаемый экземпляр, вы будете использовать порт, 443который является зарезервированным частным портом, и вы может быть в конечном итоге Socket hang upили ECONNREFUSEDошибки.

Вместо этого используйте port 3000, fe и сделайте httpзапрос.

Автор: Milkncookiez Размещён: 16.02.2016 01:00

0 плюса

1716 Репутация автора

В моем случае это было потому, что ответ приложения / json был плохо отформатирован (содержит трассировку стека). Ответ никогда не отправлялся на сервер. Это было очень сложно отлаживать, потому что не было журнала. Эта тема очень помогает мне понять, что происходит.

Автор: jmcollin92 Размещён: 03.01.2017 07:39

0 плюса

1919 Репутация автора

Если вы используете node-http-proxy, учтите эту проблему, которая приведет к ошибке зависания сокета: https://github.com/nodejitsu/node-http-proxy/issues/180 .

Для разрешения, также в этой ссылке, просто переместите объявление API-маршрута (для проксирования) в пределах экспресс-маршрутов перед express.bodyParser ().

Автор: Thinhbk Размещён: 25.02.2017 12:08

24 плюса

333 Репутация автора

Я использовал , require('http')чтобы потреблять по протоколу HTTPS службы , и он показал « socked hang up».

Тогда я использую require('https')вместо этого, и это работает.

Автор: Aekkawit Chanpen Размещён: 04.04.2017 08:42

0 плюса

5260 Репутация автора

Вчера столкнулся с этой проблемой, запустив мое веб-приложение и сервер node.js через IntelliJ IDEA 2016.3.6. Все, что мне нужно было сделать, это очистить мои куки и кеш в моем браузере Chrome.

Автор: Jordan.J.D Размещён: 05.05.2017 03:15

3 плюса

31 Репутация автора

У меня была такая же проблема во время запроса к какому-либо серверу. В моем случае мне помогло установить любое значение User-Agent в заголовках в параметрах запроса.

const httpRequestOptions = {
    hostname: 'site.address.com',
    headers: {
       'User-Agent': 'Chrome/59.0.3071.115'
    }
};

Это не общий случай и зависит от настроек сервера.

Автор: AndreyU Размещён: 05.08.2017 01:15

1 плюс

1062 Репутация автора

Я занимаюсь как веб-разработкой (Android), так и разработкой для Android, и одновременно открываю симулятор устройства Android Studio и докер, оба они используют порт 8601, что вызвало socket hang upошибку, после закрытия симулятора устройства Android Studio, и он хорошо работает на стороне узла. Не используйте симулятор устройства Android Studio и докер вместе.

Автор: Yao Li Размещён: 06.10.2017 10:07

0 плюса

116 Репутация автора

Если вы сталкиваетесь с этой ошибкой через соединение https и она возникает мгновенно, это может быть проблемой при настройке соединения SSL.

Для меня это был вопрос https://github.com/nodejs/node/issues/9845, но для вас это могло быть что-то еще. Если это проблема с ssl, то вы сможете воспроизвести его с помощью пакета nodejs tls / ssl, просто пытающегося подключиться к домену.

Автор: BrightEyed Размещён: 11.12.2017 04:12

0 плюса

4439 Репутация автора

Я думаю стоит отметить ...

Я создавал тесты для Google API. Я перехватывал запрос с помощью временного сервера, а затем пересылал их в настоящий API. Я пытался просто передать заголовки в запросе, но несколько заголовков вызывали проблему с экспрессом на другом конце.

А именно, мне пришлось удалить connection, acceptи content-lengthзаголовки перед использованием модуля запроса направить вместе.

let headers = Object.assign({}, req.headers);
delete headers['connection']
delete headers['accept']
delete headers['content-length']
res.end() // We don't need the incoming connection anymore
request({
  method: 'post',
  body: req.body,
  headers: headers,
  json: true,
  url: `http://myapi/${req.url}`
}, (err, _res, body)=>{
  if(err) return done(err);
  // Test my api response here as if Google sent it.
})
Автор: Senica Gonzalez Размещён: 08.02.2018 08:38

22 плюса

362 Репутация автора

ниже приведен простой пример, в котором я получил ту же ошибку, когда пропустил добавление прокомментированного кода в приведенном ниже примере. Раскомментирование кода req.end()решит эту проблему.

var fs = require("fs");
var https = require("https");

var options = {
    host: "en.wikipedia.org",
    path: "/wiki/George_Washington",
    port: 443,
    method: "GET"
};

var req = https.request(options, function (res) {
    console.log(res.statusCode);
});


// req.end();
Автор: Shiyas Cholamukhath Размещён: 09.02.2018 11:58

3 плюса

3297 Репутация автора

Для requestпользователей модуля

Таймауты

Существует два основных типа тайм-аутов: тайм- ауты соединения и тайм- ауты чтения . Таймаут соединения возникает , если тайм - аут попал в то время как ваш клиент пытается установить соединение с удаленным компьютером (соответствующий connect()вызов на сокете). Таймаут происходит каждый раз , когда сервер слишком медленно , чтобы отправить обратно часть ответа.

Обратите внимание , что тайм - аут соединений испускает ETIMEDOUTошибку, и прочитать таймауты испустить ECONNRESETошибку.

Автор: Константин Ван Размещён: 12.02.2018 09:47

2 плюса

155 Репутация автора

Кроме того, причина может быть из - за использования appэкземпляра expressвместо того , чтобы serverс const server = http.createServer(app)при создании серверного сокета.

Неправильно

const express = require('express');
const http = require('http');
const WebSocket = require('ws');


const app = express();

app.use(function (req, res) {
  res.send({ msg: "hello" });
});

const wss = new WebSocket.Server({ server: app }); // will throw error while connecting from client socket

app.listen(8080, function listening() {
  console.log('Listening on %d', server.address().port);
});

Верный

const express = require('express');
const http = require('http');
const WebSocket = require('ws');


const app = express();

app.use(function (req, res) {
  res.send({ msg: "hello" });
});

const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

server.listen(8080, function listening() {
  console.log('Listening on %d', server.address().port);
});
Автор: Nikolay Podolnyy Размещён: 13.03.2018 07:45

4 плюса

1418 Репутация автора

Это вызвало у меня проблемы, так как я делал все, что перечислено здесь, но все равно получал ошибки. Оказывается, что вызов req.abort () на самом деле выдает ошибку с кодом ECONNRESET, поэтому вам действительно нужно отловить это в своем обработчике ошибок.

req.on('error', function(err) {
    if (err.code === "ECONNRESET") {
        console.log("Timeout occurs");
        return;
    }
    //handle normal errors
});
Автор: Jeffrey Harmon Размещён: 12.06.2018 03:53

0 плюса

2464 Репутация автора

В моем случае это была не ошибка, а ожидаемое поведение для браузера Chrome. Chrome поддерживает соединение tls (для скорости, я думаю), но сервер node.js останавливает его через 2 минуты, и вы получаете сообщение об ошибке.

Если вы попытаетесь выполнить запрос GET с помощью пограничного браузера, ошибки не будет вообще. Если вы закроете окно Chrome - вы сразу получите ошибку.

Так что делать? 1) Вы можете отфильтровать эти ошибки, потому что они на самом деле не являются ошибками. 2) Может быть, есть лучшее решение :)

Автор: RTW Размещён: 03.01.2019 01:35
Вопросы из категории :
32x32