request是用Node.js編寫(xiě)的一個(gè)HTTP客戶端庫(kù)面哼,用于發(fā)出HTTP/HTTPS協(xié)議的請(qǐng)求,項(xiàng)目主頁(yè)在此扫步。它提供回調(diào)風(fēng)格的API魔策,例如下面的代碼將訪問(wèn)example.com并將頁(yè)面源碼輸出到終端
'use strict';
const request = require('request');
request('http://example.com/', function (error, response, body) {
if (error) {
console.error(error);
} else {
console.log(body);
}
});
保存到文件request-example.js中,在命令行執(zhí)行下列代碼即可看到效果
node request-example.js
除了網(wǎng)頁(yè)之外河胎,request當(dāng)然也可以請(qǐng)求HTTP協(xié)議的服務(wù)端API闯袒。但如果只是想要請(qǐng)求一下接口,而不需要獲得響應(yīng)結(jié)果時(shí),可能會(huì)寫(xiě)出下面這樣的代碼
'use strict';
const request = require('request');
request('http://example.com/');
這樣確實(shí)可以對(duì)服務(wù)端API發(fā)出請(qǐng)求政敢,可以在本地啟動(dòng)一個(gè)Web服務(wù)器驗(yàn)證這一點(diǎn)原茅,例如使用下列命令
python -m SimpleHTTPServer 8000
就可以啟動(dòng)一個(gè)監(jiān)聽(tīng)8000端口的HTTP服務(wù)器了。將request-example.js文件中的目標(biāo)地址改為http://127.0.0.1:8000/后再執(zhí)行堕仔,就可以看到Web服務(wù)器在終端輸出了一行訪問(wèn)日志擂橘。
可如果請(qǐng)求服務(wù)端API的過(guò)程中遇到了問(wèn)題,上面的代碼將會(huì)怎樣呢摩骨?我最開(kāi)始認(rèn)為通贞,既然回調(diào)函數(shù)的第一個(gè)參數(shù)是用于接收可能出現(xiàn)的錯(cuò)誤的,那么如果沒(méi)有回調(diào)函數(shù)恼五,這個(gè)錯(cuò)誤無(wú)處可去昌罩,這個(gè)它應(yīng)該會(huì)被安靜地丟掉。為了驗(yàn)證這個(gè)猜想灾馒,我把將本地的Web服務(wù)器關(guān)閉茎用,然后再執(zhí)行這段Node.js代碼,結(jié)果在我的電腦上睬罗,node輸出了如下信息
events.js:160
throw er; // Unhandled 'error' event
^
Error: connect ECONNREFUSED 127.0.0.1:8000
at Object.exports._errnoException (util.js:1022:11)
at exports._exceptionWithHostPort (util.js:1045:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1087:14)
出乎意料轨功,request居然拋出了異常,這是為什么呢容达?閱讀request的源代碼后發(fā)現(xiàn)古涧,如果調(diào)用request時(shí)提供了回調(diào)函數(shù),那么下面這段代碼會(huì)使用這個(gè)回調(diào)函數(shù)來(lái)處理error事件
if (!self._callback && self.callback) {
self._callback = self.callback
self.callback = function () {
if (self._callbackCalled) {
return // Print a warning maybe?
}
self._callbackCalled = true
self._callback.apply(self, arguments)
}
self.on('error', self.callback.bind()) // <-- 就是這一句
self.on('complete', self.callback.bind(self, null))
}
而如果沒(méi)有傳入回調(diào)函數(shù)花盐,那么當(dāng)請(qǐng)求對(duì)象(self.req
)收到error事件時(shí)羡滑,會(huì)調(diào)用onRequestError
方法,并在Request
對(duì)象上主動(dòng)發(fā)送'error'
事件算芯。由于沒(méi)有處理'error'
事件的回調(diào)函數(shù)柒昏,因此在onRequestError
方法中拋出的錯(cuò)誤,將會(huì)成為一個(gè)'uncaughtException'
熙揍,一直拋出到node進(jìn)程這一級(jí)(因?yàn)閷?duì)node的事件機(jī)制不是很清楚职祷,這一部分只是我的猜測(cè))。如果沒(méi)有對(duì)'uncaughtException'
事件進(jìn)行處理诈嘿,node進(jìn)程就會(huì)被終止并輸出上文所看到的錯(cuò)誤信息堪旧。
因此削葱,如果要在不傳遞回調(diào)函數(shù)的情況下忽略可能發(fā)生的網(wǎng)絡(luò)錯(cuò)誤奖亚,應(yīng)當(dāng)使用下面的代碼
'use strict';
const request = require('request');
process.on('uncaughtException', function (error) {
console.error('catch uncaughtException', error);
});
request('http://127.0.0.1:8000/');
老實(shí)說(shuō),上面的代碼還不如寫(xiě)成
'use strict';
const request = require('request');
request('http://127.0.0.1:8000/', function (error) {
console.error(error);
});
我的目的只在于請(qǐng)求服務(wù)端API而不在意失敗析砸,因此最終的代碼如下
'use strict';
const request = require('request');
request('http://127.0.0.1:8000/', function () {});