mirror of
https://github.com/eggjs/egg.git
synced 2024-12-04 07:14:30 +00:00
Fixture for some English comments in syntax. Co-authored-by: Maledong <maledong_github@outlook.com>
123 lines
3.8 KiB
JavaScript
123 lines
3.8 KiB
JavaScript
'use strict';
|
|
|
|
const dns = require('mz/dns');
|
|
const LRU = require('ylru');
|
|
const HttpClient = require('./httpclient');
|
|
const utility = require('utility');
|
|
const utils = require('./utils');
|
|
|
|
const IP_REGEX = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
|
const DNSLOOKUP = Symbol('DNSCacheHttpClient#dnslookup');
|
|
const UPDATE_DNS = Symbol('DNSCacheHttpClient#updateDNS');
|
|
|
|
class DNSCacheHttpClient extends HttpClient {
|
|
constructor(app) {
|
|
super(app);
|
|
this.dnsCacheLookupInterval = this.app.config.httpclient.dnsCacheLookupInterval;
|
|
this.dnsCache = new LRU(this.app.config.httpclient.dnsCacheMaxLength);
|
|
}
|
|
|
|
request(url, args, callback) {
|
|
// request(url, callback)
|
|
if (typeof args === 'function') {
|
|
callback = args;
|
|
args = null;
|
|
}
|
|
|
|
// the callback style
|
|
if (callback) {
|
|
this.app.deprecate('[dnscache_httpclient] We now support async for this function, so callback isn\'t recommended.');
|
|
// disable dns cache in request by args handle
|
|
if (args && args.enableDNSCache === false) {
|
|
super.request(url, args, callback);
|
|
return;
|
|
}
|
|
this[DNSLOOKUP](url, args)
|
|
.then(result => {
|
|
return super.request(result.url, result.args);
|
|
})
|
|
.then(result => process.nextTick(() => callback(null, result.data, result.res)))
|
|
.catch(err => process.nextTick(() => callback(err)));
|
|
return;
|
|
}
|
|
|
|
// the Promise style
|
|
return (async () => {
|
|
// disable dns cache in request by args handle
|
|
if (args && args.enableDNSCache === false) {
|
|
return super.request(url, args);
|
|
}
|
|
const result = await this[DNSLOOKUP](url, args);
|
|
return super.request(result.url, result.args);
|
|
})();
|
|
}
|
|
|
|
async [DNSLOOKUP](url, args) {
|
|
let parsed;
|
|
if (typeof url === 'string') {
|
|
parsed = utils.safeParseURL(url);
|
|
// invalid url or relative url
|
|
if (!parsed) return { url, args };
|
|
} else {
|
|
parsed = url;
|
|
}
|
|
// hostname must exists
|
|
const hostname = parsed.hostname;
|
|
|
|
// don't lookup when hostname is IP
|
|
if (hostname && IP_REGEX.test(hostname)) {
|
|
return { url, args };
|
|
}
|
|
|
|
args = args || {};
|
|
args.headers = args.headers || {};
|
|
// set when host header doesn't exist
|
|
if (!args.headers.host && !args.headers.Host) {
|
|
// host must combine with hostname:port, node won't use `parsed.host`
|
|
args.headers.host = parsed.port ? `${hostname}:${parsed.port}` : hostname;
|
|
}
|
|
|
|
const record = this.dnsCache.get(hostname);
|
|
const now = Date.now();
|
|
if (record) {
|
|
if (now - record.timestamp >= this.dnsCacheLookupInterval) {
|
|
// make sure the next request doesn't refresh dns query
|
|
record.timestamp = now;
|
|
this[UPDATE_DNS](hostname, args).catch(err => this.app.emit('error', err));
|
|
}
|
|
|
|
return { url: formatDnsLookupUrl(hostname, url, record.ip), args };
|
|
}
|
|
|
|
const address = await this[UPDATE_DNS](hostname, args);
|
|
return { url: formatDnsLookupUrl(hostname, url, address), args };
|
|
}
|
|
|
|
async [UPDATE_DNS](hostname, args) {
|
|
const logger = args.ctx ? args.ctx.coreLogger : this.app.coreLogger;
|
|
try {
|
|
const [ address ] = await dns.lookup(hostname, { family: 4 });
|
|
logger.info('[dnscache_httpclient] dns lookup success: %s => %s',
|
|
hostname, address);
|
|
this.dnsCache.set(hostname, { timestamp: Date.now(), ip: address });
|
|
return address;
|
|
} catch (err) {
|
|
err.message = `[dnscache_httpclient] dns lookup error: ${hostname} => ${err.message}`;
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
module.exports = DNSCacheHttpClient;
|
|
|
|
function formatDnsLookupUrl(host, url, address) {
|
|
if (typeof url === 'string') return url.replace(host, address);
|
|
const urlObj = utility.assign({}, url);
|
|
urlObj.hostname = urlObj.hostname.replace(host, address);
|
|
if (urlObj.host) {
|
|
urlObj.host = urlObj.host.replace(host, address);
|
|
}
|
|
return urlObj;
|
|
}
|