2016-08-19 9 views
5

जावास्क्रिप्ट कोड NodeJS में मार डाला निम्नलिखित पर विचार करें:NodeJS: http.ClientRequest विशिष्ट परिदृश्य में दो बार त्रुटि ईवेंट सक्रिय

// create ClientRequest 
// port 55555 is not opened 
var req = require('http').request('http://localhost:55555', function() { 
    console.log('should be never reached'); 
}); 

function cb() { 
    throw new Error(); 
} 

req.on('error', function(e) { 
console.log(e); 
cb(); 
}); 

// exceptions handler 
process.on('uncaughtException', function() { 
console.log('exception caught. doing some async clean-up before exit...'); 
setTimeout(function() { 
    console.log('exiting'); 
    process.exit(1); 
}, 2000); 
}); 

// send request 
req.end(); 

अपेक्षित उत्पादन:

{ Error: connect ECONNREFUSED 127.0.0.1:55555 
    at Object.exports._errnoException (util.js:1026:11) 
    at exports._exceptionWithHostPort (util.js:1049:20) 
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1081:14) 
    code: 'ECONNREFUSED', 
    errno: 'ECONNREFUSED', 
    syscall: 'connect', 
    address: '127.0.0.1', 
    port: 55555 } 
exception caught. doing some async clean-up before exit... 
exiting 

वास्तविक उत्पादन:

{ Error: connect ECONNREFUSED 127.0.0.1:55555 
    at Object.exports._errnoException (util.js:1026:11) 
    at exports._exceptionWithHostPort (util.js:1049:20) 
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1081:14) 
    code: 'ECONNREFUSED', 
    errno: 'ECONNREFUSED', 
    syscall: 'connect', 
    address: '127.0.0.1', 
    port: 55555 } 
exception caught. doing some async clean-up before exit... 
{ Error: socket hang up 
    at createHangUpError (_http_client.js:252:15) 
    at Socket.socketCloseListener (_http_client.js:284:23) 
    at emitOne (events.js:101:20) 
    at Socket.emit (events.js:188:7) 
    at TCP._handle.close [as _onclose] (net.js:492:12) code: 'ECONNRESET' } 
exception caught. doing some async clean-up before exit... 
exiting 

जैसा कि आप देख सकते हैं, http.ClientRequest (या शायद stream.Writable?) त्रुटि घटना दो बार आग लगती है, पहले ECONNREFUSED और aft के साथ एर अपवाद पकड़ा गया है, ECONNRESET।

ऐसा नहीं होता है अगर हम httpTClientRequest त्रुटि हैंडलर में कॉलबैक को अतुल्यकालिक रूप से निष्पादित करते हैं तो अगलीटिक या सेटटाइमआउट का उपयोग करते हुए, उदा। यह परिवर्तन अपेक्षित व्यवहार देता है:

req.on('error', function(e) { 
console.log(e); 
process.nextTick(cb); 
}); 

क्या कोई यह समझा सकता है कि यह क्यों हो रहा है और यदि यह एक बग या अपेक्षित काम करता है? व्यवहार नवीनतम नोड 4.x और नोड 6.x में समान है।

धन्यवाद!

उत्तर

3

सार

दिक्कत यह है कि आप श्रोता कॉलबैक अंदर ध्यान में न आया त्रुटि फेंक रहे है। नोड जानबूझकर अप्रत्याशित अपवादों को संभाल नहीं लेता है, इसलिए परिणाम यह है कि इस त्रुटि के बाद सामान्य रूप से चलने वाला कोड छोड़ दिया गया है क्योंकि नियंत्रण को उचित पकड़ पर जाना चाहिए (इस मामले में आपके बेजोड़ अपवाद प्रबंधन के लिए सभी तरह से।) यह कुछ कारण बनता है चीजें नहीं होने वाली हैं, लेकिन सबसे ध्यान देने योग्य यह है कि HTTPRequest इस बात से अवगत नहीं है कि सॉकेट बंद होने के लिए इसे वापस बुलाए जाने पर यह सफलतापूर्वक एक त्रुटि को उत्सर्जित करता है।

विवरण और संदर्भ

नोड के सामान्य दर्शन इस पैटर्न एक programmer error के रूप में है कि एक विफलता तक पहुँचने के लिए अनुमति दी जानी चाहिए not to trap unexpected throws और नोड व्यवहार करता है। (प्रलेखन किसी इवेंट श्रोता कॉलबैक के लिए एपीआई के बारे में स्पष्ट नहीं है, लेकिन यह कोई उदाहरण भी प्रदान नहीं करता है जहां स्ट्रीम एपीआई के डेवलपर पक्ष पर एमिटर को संभालने पर संभावना पर विचार करने के लिए कोई अपवाद या निर्देश फेंकता है।)

कब अपने अपवाद emitter, और बाद में श्रोताओं और इसकी सफाई और सॉकेट नहीं होती है के अंकन के बाकी अप करने के लिए प्रसारित, ClientRequest के कारण इसे फिर से एक त्रुटि प्रदान करने की जरूरत में सोचने के लिए:

emitter कि आपके कॉलबैक फेंकता पीछा किया जाता है दूसरी त्रुटि को दबाने के लिए कोड द्वारा:

req.emit('error', err); 
// For Safety. Some additional errors might fire later on 
// and we need to make sure we don't double-fire the error event. 
req.socket._hadError = true; 

के बाद से अपने फेंक वहाँ पकड़े नहीं किया गया था, इस चर के लिए Check तो _hadError पाता अभी भी सेट नहीं होने पर:

if (!req.res && !req.socket._hadError) { 
    // 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.socket._hadError = true; 
} 

आप अपने त्रुटि एक और अतुल्यकालिक ब्लॉक में फेंक तो आप सॉकेट के बाकी नहीं रोक रहे हैं पुश करते हैं जारी रखने के लिए सफाई प्रक्रिया कुछ अन्य फ़ंक्शन स्टैक में अपवाद होगा।

कुछ अन्य मामलों में नोड सावधानी बरतता है जब कॉलबैक कॉल करता है और यह पहले से क्या सेट करता है।लेकिन यह काफी हद तक, कॉलबैक कुछ वैकल्पिक सफाई, आदि करने के लिए अनुमति देने के लिए किया जाता है के रूप में इस comment में देखी गई:

we set destroyed to true before firing error callbacks in order 
to make it re-entrance safe in case Socket.prototype.destroy() 
is called within callbacks 

_hadError स्थापित करने और आप के लिए यह दूसरा त्रुटि को दबाने होगा उत्सर्जक के आदेश गमागमन और यह है कि दिए गए सुरक्षित लगता है लगता है कि केवल _hadError चेक है। लेकिन:

  • इस तो वह नकारात्मक त्रुटि कॉलबैक कि एक त्रुटि

  • यह अभी भी छोड़ देंगे दौरान कनेक्शन की स्थिति की जांच करने की कोशिश को प्रभावित करेंगे भविष्य में और अधिक त्रुटियों को दबा के लिए प्रयोग किया जाता है आंशिक रूप से साफ राज्य में सॉकेट जो लंबे समय तक रहने वाले कार्यक्रमों के लिए अच्छा नहीं है।

तो मैं आम तौर पर कहेंगे यह बेहतर है सीधे कॉलबैक में अपवाद नहीं फेंक जब तक आप एक असामान्य स्थिति है जहाँ सामान्य आंतरिक हैंडलिंग रोका या ओवरराइड करने के लिए है है।

संबंधित मुद्दे