Node의 http.request ()에 시간 제한을 설정하는 방법은 무엇입니까?


94

운없이 http.request를 사용하는 HTTP 클라이언트에서 시간 제한을 설정하려고합니다. 지금까지 내가 한 일은 다음과 같습니다.

var options = { ... }
var req = http.request(options, function(res) {
  // Usual stuff: on(data), on(end), chunks, etc...
}

/* This does not work TOO MUCH... sometimes the socket is not ready (undefined) expecially on rapid sequences of requests */
req.socket.setTimeout(myTimeout);  
req.socket.on('timeout', function() {
  req.abort();
});

req.write('something');
req.end();

힌트가 있습니까?


1
http.request에 대해 뭔가 다른 존재하는 경우) (이 답변 발견 (너무 작동)하지만 난 궁금 stackoverflow.com/questions/6129240/...
클라우디오

답변:


28

답변 을 명확히하기 위해 :

이제 timeout옵션 및 해당 요청 이벤트 를 사용할 수 있습니다.

// set the desired timeout in options
const options = {
    //...
    timeout: 3000,
};

// create a request
const request = http.request(options, response => {
    // your callback here
});

// use its "timeout" event to abort the request
request.on('timeout', () => {
    request.abort();
});

1
이것이 단지 다른 것인지 궁금합니다setTimeout(req.abort.bind(req), 3000);
Alexander Mills

@AlexanderMills, 그런 다음 요청이 제대로 작동하면 시간 초과를 수동으로 지우고 싶을 것입니다.
Sergei Kovalenko

4
이는 엄격히 connect제한 시간이며 소켓이 설정되면 아무 효과가 없습니다. 따라서 소켓을 너무 오랫동안 열어 두는 서버에는 도움이되지 않습니다 (setTimeout으로 직접 롤링해야 함). timeout : A number specifying the socket timeout in milliseconds. This will set the timeout before the socket is connected.
UpTheCreek

이것은 중단 된 연결 시도에서 내가 찾고있는 것입니다. 중단 된 연결은 수신하지 않는 서버의 포트에 액세스하려고 할 때 약간 발생할 수 있습니다. BTW, API가 request.destroy( abort더 이상 사용되지 않음)로 변경되었습니다 . 또한 이것은 다음과 다릅니다.setTimeout
dturvene

91

2019 업데이트

이제 이것을보다 우아하게 처리 할 수있는 다양한 방법이 있습니다. 이 스레드에서 다른 답변을 참조하십시오. 기술은 빠르게 움직이므로 답변은 종종 상당히 빨리 구식이 될 수 있습니다. 내 대답은 여전히 ​​작동하지만 대안도 살펴볼 가치가 있습니다.

2012 년 답변

코드를 사용할 때 문제는 소켓 객체에 항목을 설정하기 전에 요청에 소켓이 할당 될 때까지 기다리지 않았다는 것입니다. 모두 비동기이므로 :

var options = { ... }
var req = http.request(options, function(res) {
  // Usual stuff: on(data), on(end), chunks, etc...
});

req.on('socket', function (socket) {
    socket.setTimeout(myTimeout);  
    socket.on('timeout', function() {
        req.abort();
    });
});

req.on('error', function(err) {
    if (err.code === "ECONNRESET") {
        console.log("Timeout occurs");
        //specific error treatment
    }
    //other error treatment
});

req.write('something');
req.end();

요청에 소켓 개체가 할당되면 'socket'이벤트가 시작됩니다.


이것은 실제로 완전히 의미가 있습니다. 문제는 이제이 특정 문제를 테스트 할 수 없다는 것입니다 (시간이 지남 ...). 그래서 지금은 답변 만 찬성 할 수 있습니다. :) 감사합니다.
Claudio

걱정 마. 내가 아는 한 최신 버전의 노드에서만 작동합니다. 이전 버전 (5.0.3-pre)에서 테스트했는데 소켓 이벤트가 발생하지 않았습니다.
롭 에반스

1
이를 처리하는 다른 방법은 bog 표준 setTimeout 호출을 사용하는 것입니다. 다음과 같이 setTimeout ID를 유지해야합니다. var id = setTimeout (...); 데이터 등을 받으면 취소 할 수 있습니다. 좋은 방법은 요청 객체 자체에 저장 한 다음 데이터가 있으면 clearTimeout에 저장하는 것입니다.
Rob Evans

1
당신은 누락되었습니다); req.on의 끝에. 6자가 아니기 때문에 편집 할 수 없습니다.
JR Smith

이것은 효과가 있지만 (감사합니다!) 응답은 결국 도착할 것임을 명심하십시오. req.abort()현재 표준 기능이 아닌 것 같습니다. 따라서에서 socket.on당신은 같은 변수를 설정 할 수 있습니다 timeout = true응답 핸들러에 적절 타임 아웃을 한 후 처리
조나단 벤

40

현재 요청 객체에 대해 직접이 작업을 수행하는 방법이 있습니다.

request.setTimeout(timeout, function() {
    request.abort();
});

이것은 소켓 이벤트에 바인딩 한 다음 타임 아웃을 생성하는 바로 가기 메서드입니다.

참조 : Node.js v0.8.8 매뉴얼 및 문서


3
request.setTimeout "소켓의 비활성 시간 제한 (밀리 초) 후에 소켓을 시간 제한으로 설정합니다." 이 질문은 활동에 관계없이 요청 시간 초과에 관한 것이라고 생각합니다.
ostergaard

관련 소켓을 직접 사용하는 아래 답변과 동일하게 req.abort ()는 on ( 'error') 등으로 처리해야하는 오류 이벤트를 발생시킵니다.
KLoozen

4
request.setTimeout은 요청을 중단하지 않습니다. timeout 콜백에서 abort를 수동으로 호출해야합니다.
Udhaya

18

Rob Evans anwser는 나를 위해 올바르게 작동하지만 request.abort ()를 사용하면 처리되지 않은 소켓 중단 오류가 발생합니다.

요청 개체에 대한 오류 처리기를 추가해야했습니다.

var options = { ... }
var req = http.request(options, function(res) {
  // Usual stuff: on(data), on(end), chunks, etc...
}

req.on('socket', function (socket) {
    socket.setTimeout(myTimeout);  
    socket.on('timeout', function() {
        req.abort();
    });
}

req.on('error', function(err) {
    if (err.code === "ECONNRESET") {
        console.log("Timeout occurs");
        //specific error treatment
    }
    //other error treatment
});

req.write('something');
req.end();

3
myTimeout기능 은 어디에 있습니까? (편집 : 문서 내용 : 시간 초과 이벤트 nodejs.org/api/…에 바인딩하는 것과 동일 )
Ben Muircroft

공지 사항 ECONNRESET두 가지 경우에 발생할 수 있습니다 : 클라이언트 닫히고는 소켓과 서버 연결을 닫습니다. 이 호출하여 클라이언트에 의해 수행 된 경우 확인하려면 abort()이 것은 spceial입니다 abort이벤트
키릴

9

더 간단한 방법이 있습니다.

setTimeout을 사용하거나 소켓으로 직접 작업하는 대신
클라이언트 사용의 'options'에서 'timeout'을 사용할 수 있습니다.

아래는 서버와 클라이언트의 코드입니다.

모듈 및 옵션 부분 :

'use strict';

// Source: https://github.com/nodejs/node/blob/master/test/parallel/test-http-client-timeout-option.js

const assert = require('assert');
const http = require('http');

const options = {
    host: '127.0.0.1', // server uses this
    port: 3000, // server uses this

    method: 'GET', // client uses this
    path: '/', // client uses this
    timeout: 2000 // client uses this, timesout in 2 seconds if server does not respond in time
};

서버 부분 :

function startServer() {
    console.log('startServer');

    const server = http.createServer();
    server
            .listen(options.port, options.host, function () {
                console.log('Server listening on http://' + options.host + ':' + options.port);
                console.log('');

                // server is listening now
                // so, let's start the client

                startClient();
            });
}

클라이언트 부분 :

function startClient() {
    console.log('startClient');

    const req = http.request(options);

    req.on('close', function () {
        console.log("got closed!");
    });

    req.on('timeout', function () {
        console.log("timeout! " + (options.timeout / 1000) + " seconds expired");

        // Source: https://github.com/nodejs/node/blob/master/test/parallel/test-http-client-timeout-option.js#L27
        req.destroy();
    });

    req.on('error', function (e) {
        // Source: https://github.com/nodejs/node/blob/master/lib/_http_outgoing.js#L248
        if (req.connection.destroyed) {
            console.log("got error, req.destroy() was called!");
            return;
        }

        console.log("got error! ", e);
    });

    // Finish sending the request
    req.end();
}


startServer();

위의 세 부분을 모두 "a.js"파일에 넣고 다음을 실행하면 :

node a.js

그러면 출력은 다음과 같습니다.

startServer
Server listening on http://127.0.0.1:3000

startClient
timeout! 2 seconds expired
got closed!
got error, req.destroy() was called!

도움이되기를 바랍니다.


2

나를 위해-여기에 덜 혼란스러운 방법이 있습니다. socket.setTimeout

var request=require('https').get(
    url
   ,function(response){
        var r='';
        response.on('data',function(chunk){
            r+=chunk;
            });
        response.on('end',function(){
            console.dir(r);            //end up here if everything is good!
            });
        }).on('error',function(e){
            console.dir(e.message);    //end up here if the result returns an error
            });
request.on('error',function(e){
    console.dir(e);                    //end up here if a timeout
    });
request.on('socket',function(socket){
    socket.setTimeout(1000,function(){
        request.abort();                //causes error event ↑
        });
    });

2

@douwe에 대한 답변을 자세히 설명하면 http 요청에 시간 제한을 두는 곳입니다.

// TYPICAL REQUEST
var req = https.get(http_options, function (res) {                                                                                                             
    var data = '';                                                                                                                                             

    res.on('data', function (chunk) { data += chunk; });                                                                                                                                                                
    res.on('end', function () {
        if (res.statusCode === 200) { /* do stuff with your data */}
        else { /* Do other codes */}
    });
});       
req.on('error', function (err) { /* More serious connection problems. */ }); 

// TIMEOUT PART
req.setTimeout(1000, function() {                                                                                                                              
    console.log("Server connection timeout (after 1 second)");                                                                                                                  
    req.abort();                                                                                                                                               
});

this.abort ()도 좋습니다.


1

아래와 같이 요청에 대한 참조를 전달해야합니다.

var options = { ... }
var req = http.request(options, function(res) {
  // Usual stuff: on(data), on(end), chunks, etc...
});

req.setTimeout(60000, function(){
    this.abort();
}).bind(req);
req.write('something');
req.end();

요청 오류 이벤트가 트리거됩니다.

req.on("error", function(e){
       console.log("Request Error : "+JSON.stringify(e));
  });


bind (req) 추가는 나를 위해 아무것도 변경하지 않았습니다. 이 경우 bind는 무엇을합니까?
SpiRail

-1

궁금합니다. net.sockets대신 스트레이트를 사용하면 어떻게 되나요? 다음은 테스트 목적으로 만든 몇 가지 샘플 코드입니다.

var net = require('net');

function HttpRequest(host, port, path, method) {
  return {
    headers: [],
    port: 80,
    path: "/",
    method: "GET",
    socket: null,
    _setDefaultHeaders: function() {

      this.headers.push(this.method + " " + this.path + " HTTP/1.1");
      this.headers.push("Host: " + this.host);
    },
    SetHeaders: function(headers) {
      for (var i = 0; i < headers.length; i++) {
        this.headers.push(headers[i]);
      }
    },
    WriteHeaders: function() {
      if(this.socket) {
        this.socket.write(this.headers.join("\r\n"));
        this.socket.write("\r\n\r\n"); // to signal headers are complete
      }
    },
    MakeRequest: function(data) {
      if(data) {
        this.socket.write(data);
      }

      this.socket.end();
    },
    SetupRequest: function() {
      this.host = host;

      if(path) {
        this.path = path;
      }
      if(port) {
        this.port = port;
      }
      if(method) {
        this.method = method;
      }

      this._setDefaultHeaders();

      this.socket = net.createConnection(this.port, this.host);
    }
  }
};

var request = HttpRequest("www.somesite.com");
request.SetupRequest();

request.socket.setTimeout(30000, function(){
  console.error("Connection timed out.");
});

request.socket.on("data", function(data) {
  console.log(data.toString('utf8'));
});

request.WriteHeaders();
request.MakeRequest();

소켓 시간 제한을 사용하고 두 개의 요청을 차례로 발행하면 (첫 번째 요청이 완료 될 때까지 기다리지 않고) 두 번째 요청에 정의되지 않은 소켓이 있습니다 (적어도 시간 제한을 설정하려는 순간). 소켓의 on ( "ready") 같은 것 ... 모르겠어요.
Claudio

@Claudio 코드를 업데이트하여 여러 요청이 이루어지고 있음을 보여줄 수 있습니까?
onteria_ 2011 년

1
물론 ... 조금 길고 이것이 문제가되지 않는다면 paste2.org를 사용했습니다. paste2.org/p/1448487
Claudio

@Claudio Hmm 좋습니다. 테스트 환경을 설정하고 테스트 코드를 작성하는 데 시간이 걸릴 것입니다. 내 대답은 내일 (태평양 표준시)에 FYI로 올 수 있습니다
onteria_

@Claudio가 실제로 코드를 살펴보면 오류와 일치하지 않는 것 같습니다. setTimeout이 정의되지 않은 값에 대해 호출되고 있다고 말하고 있지만이를 호출하는 방식은 글로벌 버전을 통하는 것이므로 정의되지 않을 수있는 방법이 없으므로 혼란 스러울 수 있습니다.
onteria_ 2011 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.