2011-06-02 200 views
67

我試圖設置HTTP客戶端上使用http.request沒有運氣的超時。到目前爲止我做的是這樣的:如何在Node中設置http.request()的超時時間?

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()http://stackoverflow.com/questions/6129240/how-to-set-timeout-for-http-createclient -in-node-js – Claudio 2011-06-02 13:22:29

回答

0

好奇,如果您直接使用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(); 
+0

如果我使用套接字超時,並且一個接一個地發出兩個請求(不等待第一個完成),第二個請求的套接字未定義(至少在我嘗試設置超時)..也許應該有一些東西就像(「準備好」)在插座上...我不知道。 – Claudio 2011-06-02 17:18:48

+0

@Claudio你可以更新你的代碼來顯示多個請求嗎? – 2011-06-02 17:25:55

+1

當然......這有點長,我用paste2.org,如果這不是問題:http://paste2.org/p/1448487 – Claudio 2011-06-02 17:42:47

79

使用你的代碼,問題是你有沒有等待一個插座,以試圖設置的東西Socket對象之前被分配到請求。它們都是異步的:

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

當請求被分配一個套接字對象時,會觸發'套接字'事件。

+0

這確實是完全有意義的。問題是,現在我無法測試這個特定問題(時間流逝......)。所以我現在只能讚揚答案:)謝謝。 – Claudio 2012-03-29 13:07:28

+0

不用擔心。請記住,據我所知,這隻適用於最新版本的節點。我測試了以前的版本(5.0.3-pre),我認爲它並沒有觸發套接字事件。 – 2012-03-29 16:21:31

+1

處理這個問題的另一種方法是使用一個bog標準的setTimeout調用。你需要保持setTimeout id爲:var id = setTimeout(...);這樣你可以取消它,如果你收到一個數據等。一個好方法是將它存儲在請求對象本身,然後clearTimeout,如果你有一些數據。 – 2012-03-29 16:23:45

28

這時有直接請求對象上做到這一點的方法:

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

這是結合到插座事件的快捷方式,然後創建超時。

參考:Node.js v0.8.8 Manual & Documentation

+3

中正確處理超時。request.setTimeout「將套接字上的非活動超時毫秒數設置爲超時。 「我認爲這個問題是關於不考慮活動而超時的。 – ostergaard 2013-01-20 14:00:18

+0

請注意,與直接使用相關套接字的答案相同,req.abort()會導致一個錯誤事件,該事件應該由on('error')處理。 – KLoozen 2016-01-10 17:31:29

+4

request.setTimeout不會放棄請求,我們需要在超時回調中手動調用放棄。 – Udhaya 2016-02-23 05:52:04

17

的羅布·埃文斯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(); 
+1

「myTimeout」函數在哪裏? (編輯:文檔說:與綁定到超時事件相同https://nodejs.org/api/http.html#http_request_settimeout_timeout_callback) – 2016-09-20 21:08:22

+0

請注意,'ECONNRESET'可以發生在兩種情況:客戶端關閉套接字和服務器關閉連接。要通過調用'abort()'來確定它是否由客戶端完成,那麼會出現「abort」事件 – Derp 2016-11-08 09:16:37

2

您應該通過參考請求像下面

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

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 ↑ 
     }); 
    }); 
1

有更簡單的方法的不易混淆的方式。

而不是使用的setTimeout或插座直接工作,
我們可以在客戶端中的「選項」使用「超時」使用

下面是服務器和客戶端的代碼,在3個部分。

模塊和選項部分:

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

如果你把所有的上述3個部分在一個文件中,「一.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! 

希望有所幫助。