NodeJS: ¿Qué significa realmente "el socket cuelga"?
Estoy creando un raspador web con Node y Cheerio, y para un determinado sitio web aparece el siguiente error (solo ocurre en este sitio web, no en otros que intento raspar).
Sucede en una ubicación diferente cada vez, por lo que a veces es url x
lo que arroja el error, otras veces url x
está bien y es una URL completamente diferente:
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)
Esto es muy complicado de depurar, realmente no sé por dónde empezar. Para empezar, ¿qué ES un error de bloqueo del socket? ¿Es un error 404 o similar? ¿O simplemente significa que el servidor rechazó la conexión?
¡No puedo encontrar una explicación para esto en ninguna parte!
EDITAR: Aquí hay una muestra de código que (a veces) devuelve errores:
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
});
}
No hay una llamada directa para cerrar la conexión, pero estoy usando Node Request
los usos (hasta donde yo sé), http.get
por lo que esto no es necesario, ¡corríjame si me equivoco!
EDITAR 2: Aquí hay un fragmento de código real en uso que está causando errores. prodURL
y otras variables son en su mayoría selectores de jquery que se definieron anteriormente. Esto utiliza la async
biblioteca para Node.
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);
}
]);
});
}
Hay dos casos en los que socket hang up
se arroja:
Cuando eres cliente
Cuando usted, como cliente, envía una solicitud a un servidor remoto y no recibe una respuesta oportuna. Su socket finalizó, lo que arroja este error. Debería detectar este error y decidir cómo manejarlo: volver a intentar la solicitud, ponerla en cola para más tarde, etc.
Cuando eres un servidor/proxy
Cuando usted, como servidor, tal vez un servidor proxy, recibe una solicitud de un cliente, luego comienza a actuar en consecuencia (o transmite la solicitud al servidor ascendente) y antes de haber preparado la respuesta, el cliente decide cancelar/abortar. la solicitud.
Este seguimiento de pila muestra lo que sucede cuando un cliente cancela la solicitud.
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)
La línea http.js:1526:9
apunta a lo mismo socketCloseListener
mencionado por @Blender, en particular:
// 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;
}
Este es un caso típico si el cliente es un usuario del navegador. La solicitud para cargar algún recurso/página lleva mucho tiempo y los usuarios simplemente actualizan la página. Dicha acción hace que se cancele la solicitud anterior, lo que en el lado del servidor arroja este error.
Dado que este error es causado por el deseo de un cliente, no espera recibir ningún mensaje de error. Por lo tanto, no es necesario considerar este error como crítico. Simplemente ignóralo. Esto se ve favorecido por el hecho de que, ante tal error, el res
socket que escuchó su cliente, aunque todavía se puede escribir, se destruye.
console.log(res.socket.destroyed); //true
Entonces, no tiene sentido enviar nada, excepto cerrar explícitamente el objeto de respuesta:
res.end();
Sin embargo, lo que debe hacer con seguridad si es un servidor proxy que ya ha transmitido la solicitud al flujo ascendente es abortar su solicitud interna al flujo ascendente, indicando su falta de interés en la respuesta, lo que a su vez le informará al flujo ascendente. servidor para, tal vez, detener una operación costosa.
Eche un vistazo a la fuente :
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;
}
}
El mensaje se emite cuando el servidor nunca envía una respuesta.
Un caso que vale la pena mencionar: cuando me conecto de Node.js a Node.js usando Express, aparece "el socket cuelga" si no le prefiero "/" a la ruta URL solicitada.