request是用Node.js编写的一个HTTP客户端库,用于发出HTTP/HTTPS协议的请求,项目主页在此。它提供回调风格的API,例如下面的代码将访问example.com并将页面源码输出到终端
'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中,在命令行执行下列代码即可看到效果
node request-example.js
除了网页之外,request当然也可以请求HTTP协议的服务端API。但如果只是想要请求一下接口,而不需要获得响应结果时,可能会写出下面这样的代码
'use strict';
const request = require('request');
request('http://example.com/');
这样确实可以对服务端API发出请求,可以在本地启动一个Web服务器验证这一点,例如使用下列命令
python -m SimpleHTTPServer 8000
就可以启动一个监听8000端口的HTTP服务器了。将request-example.js文件中的目标地址改为http://127.0.0.1:8000/后再执行,就可以看到Web服务器在终端输出了一行访问日志。
可如果请求服务端API的过程中遇到了问题,上面的代码将会怎样呢?我最开始认为,既然回调函数的第一个参数是用于接收可能出现的错误的,那么如果没有回调函数,这个错误无处可去,这个它应该会被安静地丢掉。为了验证这个猜想,我把将本地的Web服务器关闭,然后再执行这段Node.js代码,结果在我的电脑上,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的源代码后发现,如果调用request时提供了回调函数,那么下面这段代码会使用这个回调函数来处理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))
}
而如果没有传入回调函数,那么当请求对象(self.req
)收到error事件时,会调用onRequestError
方法,并在Request
对象上主动发送'error'
事件。由于没有处理'error'
事件的回调函数,因此在onRequestError
方法中抛出的错误,将会成为一个'uncaughtException'
,一直抛出到node进程这一级(因为对node的事件机制不是很清楚,这一部分只是我的猜测)。如果没有对'uncaughtException'
事件进行处理,node进程就会被终止并输出上文所看到的错误信息。
因此,如果要在不传递回调函数的情况下忽略可能发生的网络错误,应当使用下面的代码
'use strict';
const request = require('request');
process.on('uncaughtException', function (error) {
console.error('catch uncaughtException', error);
});
request('http://127.0.0.1:8000/');
老实说,上面的代码还不如写成
'use strict';
const request = require('request');
request('http://127.0.0.1:8000/', function (error) {
console.error(error);
});
我的目的只在于请求服务端API而不在意失败,因此最终的代码如下
'use strict';
const request = require('request');
request('http://127.0.0.1:8000/', function () {});