NodeJS-“소켓 끊기”는 실제로 무엇을 의미합니까?


276

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)

이것은 디버깅하기가 매우 까다 롭습니다. 처음부터 시작 해야할지 모르겠습니다. 시작하려면, 무엇 인가 소켓 오류를 끊지? 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 선택기입니다. asyncNode 용 라이브러리를 사용합니다 .

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

26
소켓이 end시간 초과 기간 내에 연결 이벤트를 보내지 않음을 의미합니다 . 를 통해 cheerio 요청을받는 경우 http.request(아님 http.get). request.end()요청 전송을 마치 려면 전화 해야합니다.
user568109

1
@ user568109 request특정 http.request요청이 아닌 노드 서비스를 사용하고 있습니다 (노드를 처음 접 한다고 생각합니다). 이것은 하나입니다 : github.com/mikeal/request 이것은 자동으로 요청을 마치는 것처럼 보입니다. 편집 : 문서에 따르면 http method, defaults to GET문제가 아닙니다.
JVG

2
그렇다면 문제가되지 않아야합니다. cheerio.load를 포함하여 긁는 부분을 주석 처리하고 동일한 내용을 반환하면 어떻게됩니까? 여기서 중요한 cheerio.load것은 비동기입니다. 따라서 $로 작업을 시작하기 전에 완료되지 않을 수 있습니다.
user568109

4
또한 10+ 동시 연결과 같이 사이트를 너무 적극적으로 크롤링하면 소켓 끊기로 응답하기 시작하는 경우도 있습니다.
tobek

1
영어로 된 FYI 는 연결을 끊음으로써 전자 대화를 끝내는hang up 것을 의미 합니다 . 구식 전화를 끊기 시작했습니다.
Константин Ван

답변:


161

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)

라인 은 @Blender가 위에서 언급 한 http.js:1526:9것과 동일하게 지적합니다 socketCloseListener.

// 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();

그러나, 당신이 무엇을 해야 당신이 경우에 확실 하다 이미 상류에 요청을 전달했다 프록시 서버, 다시 상류을 말할 것이다 응답에서 관심의 부족을 나타내는 상류에 내부 요청을 중단하는 것입니다 아마도 비싼 작업을 중지하기 위해 서버.


2
클라이언트로서 요청을 더 오래 기다리게하려면 어떻게해야합니까? 35 초에 오류가 발생하고 1 분 정도 기다려야합니다.
빅 머니

나는 같은 문제에 직면하고있다. 응답을 기다릴 수 있고 하나씩 실행하는 것처럼 다음 요청을 보내기 시작할 수 있습니까?이 소켓이 전화를 끊는 방법을 알고 있습니까?
Deepak

@BigMoney 사용할 수 있습니다 setTimeout(). 이 질문을보십시오 : stackoverflow.com/questions/6214902/…
홀라

귀하의 세부 정보는 지옥에서 살아 남았습니다. 나는 업스트림 서버와 클라이언트 사이의 프록시 서버로 node.js를 사용하고 있었으며 요청시 시간 초과로 인해 사용을 잊어 버렸기 때문에이 오류가 발생했습니다. res.send , 감사
자드 YZ에게

동일한 연결을 통해 Django의 개발 웹 서버에 두 번째 요청을 할 때 클라이언트로 "소켓 끊기"를 수신 할 수 있습니다. 지원하지 않습니다 keep-alive. 그리고 고객이 기대하는 경우 오류가 발생합니다. 다음 라인을 따라 살펴 봅니다 .
x-yuri

53

소스를 살펴보십시오 .

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

서버가 응답을 보내지 않으면 메시지가 생성됩니다.


2
기능적인 관점에서 이것이 무엇을 의미하는지 설명 할 수 있습니까? 문제가되는 URL을 배열에 추가 한 다음 나중에 긁어내어 보호 장치를 구축하려고합니다. 나는 오류가 Node의 큐잉 문제 일 수 있다고 몇 곳에서 읽었으며,이를 해결하고 피하는 가장 좋은 방법을 모릅니다.
JVG

5
그러나 얼마나 오래 기다 립니까?
CommaToast 2018 년

2
"길이"를 구현 하려면 en.wikipedia.org/wiki/Exponential_backoff 를 사용해야합니다 .
Norman H

이 "소켓 끊기"는 의미가 없습니다. 이것은 nodejs 팀의 놀라운 일입니다.
puchu

45

언급 할 가치가있는 한 가지 사례 : Express를 사용하여 Node.js에서 Node.js로 연결할 때 요청 된 URL 경로 앞에 "/"를 붙이지 않으면 "소켓 끊기"가 발생합니다.


1
내 문제이고, 클라이언트와 서버 모두 순수한 HTTP Node.js를
애슐리는 윌리스

1
@silentorb : url 예제를 보여 주시겠습니까? 이 경우에도 같은 오류가 발생합니다. 감사합니다.
Pritam

4
오류 : "user / login", 성공 : "/ user / login"
silentorb

4
나는 거의 한 시간 동안 그것을 디버깅했습니다! 답장을 보았고 SH ** 생각하고 /를 추가했으며 정상적으로 작동합니다 :) 감사합니다!
다니엘 Gruszczyk

4
이 응답으로 시간을 절약했습니다!
imhotep

32

내가 사용하는 require('http')소비 HTTPS 서비스를하며 "보여 주었다 socket hang up".

그런 다음 대신에 변경 require('http')되어 require('https')작동합니다.


이것이 문제에 대한 해결책 일 수도 있지만 질문에 대한 답 은 아닙니다 . 포스터는 오류 메시지의 의미에 대한 답변을 원했습니다. 또한 이미 많은 고품질 답변이 있습니다. 귀하는 추가 가치를 제공하지 않습니다.
Johannes Dorn

19
의견 주셔서 감사합니다. 이 오류로 인해 시간이 낭비됩니다. 마지막으로, 나는이 솔루션을 시도하고 작동합니다. 공유하고 싶을뿐입니다. 다른 사람이 시간을 낭비하지 않고 고품질 답변으로 칭찬하는 데 유용하지 않기를 바랍니다.
Aekkawit Chanpen

12
@JohannesDorn 이것은 오류의 의미에 대한 암시 적 답변입니다. 그리고 그것에 유용한 것입니다.
Ulad Kasach

29

아래는 아래 예제에서 주석이 달린 코드를 추가하지 못했을 때 동일한 오류가 발생하는 간단한 예입니다. 코드 주석 처리를 제거하면 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();

2
이것은 나의 정신을 구했다 ... 고마워!
PGallagher

당신은 영웅입니다! 감사합니다.
Xenhat

17

블렌더의 답변을 확장하면 여러 상황에서 발생합니다. 내가 만나는 가장 일반적인 것은 다음과 같습니다.

  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헤더가 차단되었을 가능성이 큽니다.


3
서버가 연결을 거부 할 수있는 또 다른 이유 (QA 대신 prod로 이동할 때이 문제가 발생했습니다)는 서버가 http 대신 https 요청을 기대하는 경우입니다.
mcole

7

언급 할 가치가있는 또 다른 경우 (Linux 및 OS X의 경우)는 https요청 수행 과 같은 라이브러리를 사용 하거나 https://...로컬로 제공되는 인스턴스의 URL로 전달 443하면 예약 된 개인 포트 인 포트를 사용하고 끝나 Socket hang up거나 ECONNREFUSED오류가 발생 했을 수 있습니다 .

대신 port 3000, fe를 사용 하고 http요청하십시오.


6

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 프로토콜을 통해 데이터베이스에 연결하고 있었지만이 라이브러리 쇼를 사용하기위한 예제로 생성 된 keepalive 에이전트 (http를 사용하는 일부 기본값에 의존 함)를 nano 객체에 계속 전달했습니다.

HttpsAgent 를 사용하기 위한 간단한 변경으로 트릭을 수행했습니다.

var KeepAliveAgent = require('agentkeepalive').HttpsAgent;

1
조금 더 자세하게 말하자면, 요청이 포트 443에 대해 구성되고 요청이 https 모듈이 아닌 http 모듈을 통해 발행되면 소켓이 중단됩니다. 연결이 끊어진 이유 (SSL / TLS 협상?)에 대한 자세한 내용이 있으면 좋을 것입니다. 예를 들어 ASP.NET에서 세부 수준을 보았습니다.
Richard Collette

6

여기에 나열된 모든 작업을 수행하면서 문제가 발생했지만 여전히 오류가 발생했습니다. req.abort ()를 호출하면 실제로 ECONNRESET 코드와 함께 오류가 발생하므로 실제로 오류 처리기에서 오류를 잡아야합니다.

req.on('error', function(err) {
    if (err.code === "ECONNRESET") {
        console.log("Timeout occurs");
        return;
    }
    //handle normal errors
});

5

대한 request모듈 사용자

타임 아웃

시간 종료에는 연결 시간 종료읽기 시간 종료 의 두 가지 주요 유형이 있습니다. 연결 시간 초과는 클라이언트가 원격 컴퓨터 (에 대응에 대한 연결 설정을 시도하는 동안 타임 아웃이 충돌하는 경우 발생 connect()소켓에 호출). 읽기 제한 시간은 서버가 응답의 일부를 다시 보낼 너무 느립니다 언제든지 발생합니다.

하는 것으로 연결 시간 제한은 방출 ETIMEDOUT오류 및 읽기 시간 초과 방출 ECONNRESET오류가 발생했습니다.


3

일부 서버에 요청하는 동안 동일한 문제가 발생했습니다. 필자의 경우 요청 옵션의 헤더에서 값을 User-Agent로 설정하면 도움이되었습니다.

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

일반적인 경우는 아니며 서버 설정에 따라 다릅니다.


2

또한 이유는 from 대신에 appinstance를 사용하기 때문일 수 있습니다.expressserverconst 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);
});

1

나는 웹 (노드)과 안드로이드 개발을 모두하고 안드로이드 스튜디오 장치 시뮬레이터와 도커를 함께 열고 포트 8601을 사용합니다. socket hang up안드로이드 스튜디오 장치 시뮬레이터를 닫은 후 오류가 발생했으며 노드 측에서 잘 작동합니다. Android Studio 기기 시뮬레이터와 도커를 함께 사용하지 마십시오.


1

OCP 클러스터에서 CouchDB를 사용할 때 비슷한 오류가 발생했습니다.

const cloudantSessionStore = sessionStore.createSessionStore(
  {
    type: 'couchdb',
    host: 'https://' + credentials['host'],
    port: credentials['port'],
    dbName: 'sessions',
    options: {
      auth: {
        username: credentials['username'],
        password: credentials['password']
      },
      cache: false
    }
  }

내 CouchDB 인스턴스에 연결하려면 "https"가 아닌 "http"여야합니다. 비슷한 문제에 직면 한 사람에게 도움이되기를 바랍니다.


0

필자의 경우 응용 프로그램 / json 응답의 형식이 잘못 되었기 때문입니다 (스택 추적 포함). 응답이 서버로 전송되지 않았습니다. 로그가 없기 때문에 디버깅하기가 매우 까다 롭습니다. 이 스레드는 어떤 일이 발생하는지 이해하는 데 도움이됩니다.



0

어제 IntelliJ IDEA 2016.3.6을 통해 웹 응용 프로그램 및 node.js 서버를 실행 하여이 문제에 부딪 쳤습니다. Chrome 브라우저에서 쿠키를 삭제하고 캐시하기 만하면됩니다.


0

https 연결을 통해이 오류가 발생하고 즉시 발생하는 경우 SSL 연결을 설정하는 데 문제가있을 수 있습니다.

나 에게이 문제는 https://github.com/nodejs/node/issues/9845 였지만 당신에게는 다른 것일 수 있습니다. SSL에 문제가 있으면 도메인에 연결하려고 시도하는 nodejs tls / ssl 패키지를 사용하여이를 재생할 수 있어야합니다.


0

주목할만한 가치가 있다고 생각합니다 ...

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

0

내 경우에는 오류가 아니지만 크롬 브라우저의 예상 동작입니다. Chrome은 tls 연결을 활성 상태로 유지하지만 (속도는 제 생각에는 2 초) node.js 서버는 2 분 후에 중지하고 오류가 발생합니다.

에지 브라우저를 사용하여 GET 요청을 시도하면 전혀 오류가 없습니다. 크롬 창을 닫으면 즉시 오류가 발생합니다.

그래서 뭘 할건데? 1)이 오류는 실제로 오류가 아니기 때문에 필터링 할 수 있습니다. 2) 아마도 더 나은 해결책이 있습니다 :)


0

Electron이 "localhost"도메인 이름의 팬이 아닌 경우가 하나 더 있습니다. 내 경우에는 이것을 변경해야했습니다.

const backendApiHostUrl = "http://localhost:3000";

이에:

const backendApiHostUrl = "http://127.0.0.1:3000";

그 후 문제는 사라졌습니다.

즉, DNS 확인 (로컬 또는 원격)으로 인해 일부 문제가 발생할 수도 있습니다.


0

노드 js 코드, mongodb 연결 문자열, CORS 등 검사에 대한 긴 디버그 후 다른 포트 번호 server.listen(port);로 전환 하면 작동 postman합니다. proxy기본 설정 만 변경하지 마십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.