const Agent = require('agentkeepalive');
|
const HttpsAgent = require('agentkeepalive').HttpsAgent;
|
const urllib = require('urllib');
|
const { FrameworkBaseError } = require('egg-errors');
|
const Conf = require('../config/cache');
|
const Log = require('../log');
|
const Time = require('../utils/time');
|
|
class HttpClientError extends FrameworkBaseError {
|
get module() {
|
return 'httpclient';
|
}
|
}
|
|
class HttpClient extends urllib.HttpClient2 {
|
constructor(options = {}) {
|
|
if (Object.keys(options).length == 0) {
|
options = Conf.getValue('httpclient');
|
}
|
|
const config = Object.assign({
|
enableDNSCache: false,
|
dnsCacheLookupInterval: 10000,
|
dnsCacheMaxLength: 1000,
|
request: {
|
timeout: 5000,
|
},
|
httpAgent: {
|
keepAlive: true,
|
freeSocketTimeout: 4000,
|
maxSockets: Number.MAX_SAFE_INTEGER,
|
maxFreeSockets: 256,
|
},
|
httpsAgent: {
|
keepAlive: true,
|
freeSocketTimeout: 4000,
|
maxSockets: Number.MAX_SAFE_INTEGER,
|
maxFreeSockets: 256,
|
},
|
}, options);
|
|
normalizeConfig(config);
|
|
super({
|
defaultArgs: config.request,
|
agent: new Agent(config.httpAgent),
|
httpsAgent: new HttpsAgent(config.httpsAgent),
|
});
|
this.config = config;
|
}
|
|
request(url, args, callback) {
|
if (typeof args === 'function') {
|
callback = args;
|
args = null;
|
}
|
|
args = args || {};
|
|
// the callback style
|
if (callback) {
|
//this.app.deprecate('[httpclient] We now support async for this function, so callback isn\'t recommended.');
|
super.request(url, args)
|
.then(result => process.nextTick(() => callback(null, result.data, result.res)))
|
.catch(err => process.nextTick(() => callback(err)));
|
return;
|
}
|
|
// the Promise style
|
return super.request(url, args)
|
.catch(err => {
|
if (err.code === 'ENETUNREACH') {
|
throw HttpClientError.create(err.message, err.code);
|
}
|
throw err;
|
});
|
}
|
|
curl(url, args, callback) {
|
return this.request(url, args, callback);
|
}
|
|
requestThunk(url, args) {
|
//this.app.deprecate('[httpclient] Please use `request()` instead of `requestThunk()`');
|
return callback => {
|
this.request(url, args, (err, data, res) => {
|
if (err) {
|
return callback(err);
|
}
|
callback(null, {
|
data,
|
status: res.status,
|
headers: res.headers,
|
res,
|
});
|
});
|
};
|
}
|
}
|
|
function normalizeConfig(httpConfig) {
|
const config = httpConfig;
|
|
// compatibility
|
if (typeof config.keepAlive === 'boolean') {
|
config.httpAgent.keepAlive = config.keepAlive;
|
config.httpsAgent.keepAlive = config.keepAlive;
|
}
|
if (config.timeout) {
|
config.timeout = Time.ms(config.timeout);
|
config.httpAgent.timeout = config.timeout;
|
config.httpsAgent.timeout = config.timeout;
|
}
|
// compatibility httpclient.freeSocketKeepAliveTimeout => httpclient.freeSocketTimeout
|
if (config.freeSocketKeepAliveTimeout && !config.freeSocketTimeout) {
|
config.freeSocketTimeout = config.freeSocketKeepAliveTimeout;
|
delete config.freeSocketKeepAliveTimeout;
|
}
|
if (config.freeSocketTimeout) {
|
config.freeSocketTimeout = Time.ms(config.freeSocketTimeout);
|
config.httpAgent.freeSocketTimeout = config.freeSocketTimeout;
|
config.httpsAgent.freeSocketTimeout = config.freeSocketTimeout;
|
} else {
|
// compatibility agent.freeSocketKeepAliveTimeout
|
if (config.httpAgent.freeSocketKeepAliveTimeout && !config.httpAgent.freeSocketTimeout) {
|
config.httpAgent.freeSocketTimeout = config.httpAgent.freeSocketKeepAliveTimeout;
|
delete config.httpAgent.freeSocketKeepAliveTimeout;
|
}
|
if (config.httpsAgent.freeSocketKeepAliveTimeout && !config.httpsAgent.freeSocketTimeout) {
|
config.httpsAgent.freeSocketTimeout = config.httpsAgent.freeSocketKeepAliveTimeout;
|
delete config.httpsAgent.freeSocketKeepAliveTimeout;
|
}
|
}
|
|
if (typeof config.maxSockets === 'number') {
|
config.httpAgent.maxSockets = config.maxSockets;
|
config.httpsAgent.maxSockets = config.maxSockets;
|
}
|
if (typeof config.maxFreeSockets === 'number') {
|
config.httpAgent.maxFreeSockets = config.maxFreeSockets;
|
config.httpsAgent.maxFreeSockets = config.maxFreeSockets;
|
}
|
|
if (config.httpAgent.timeout < 30000) {
|
Log.coreLogger.warn('[ee-core] [httpclient] config.httpclient.httpAgent.timeout(%s) can\'t below 30000, auto reset to 30000',
|
config.httpAgent.timeout);
|
config.httpAgent.timeout = 30000;
|
}
|
if (config.httpsAgent.timeout < 30000) {
|
Log.coreLogger.warn('[ee-core] [httpclient] config.httpclient.httpsAgent.timeout(%s) can\'t below 30000, auto reset to 30000',
|
config.httpsAgent.timeout);
|
config.httpsAgent.timeout = 30000;
|
}
|
|
if (typeof config.request.timeout === 'string') {
|
config.request.timeout = Time.ms(config.request.timeout);
|
}
|
}
|
|
module.exports = HttpClient;
|