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.