mirror of https://github.com/certd/certd
perf: 证书检查支持自定义dns服务器
parent
0cea26c628
commit
c53bb7cf67
|
@ -34,6 +34,7 @@ import { locker } from "./util.lock.js";
|
||||||
import { mitter } from "./util.mitter.js";
|
import { mitter } from "./util.mitter.js";
|
||||||
|
|
||||||
import * as request from "./util.request.js";
|
import * as request from "./util.request.js";
|
||||||
|
export * from "./util.cache.js";
|
||||||
export const utils = {
|
export const utils = {
|
||||||
sleep,
|
sleep,
|
||||||
http,
|
http,
|
||||||
|
|
|
@ -1,8 +1,53 @@
|
||||||
// LRUCache
|
// LRUCache
|
||||||
|
|
||||||
import { LRUCache } from 'lru-cache';
|
import { LRUCache } from "lru-cache";
|
||||||
|
|
||||||
export const cache = new LRUCache<string, any>({
|
export const cache = new LRUCache<string, any>({
|
||||||
max: 1000,
|
max: 1000,
|
||||||
ttl: 1000 * 60 * 10,
|
ttl: 1000 * 60 * 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export class LocalCache<V = any> {
|
||||||
|
cache: Map<string, { value: V; expiresAt: number }>;
|
||||||
|
constructor(opts: { clearInterval?: number } = {}) {
|
||||||
|
this.cache = new Map();
|
||||||
|
setInterval(() => {
|
||||||
|
this.clearExpires();
|
||||||
|
}, opts.clearInterval ?? 5 * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key: string): V | undefined {
|
||||||
|
const entry = this.cache.get(key);
|
||||||
|
if (!entry) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否过期
|
||||||
|
if (Date.now() > entry.expiresAt) {
|
||||||
|
this.cache.delete(key);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key: string, value: V, ttl = 300000) {
|
||||||
|
// 默认5分钟 (300000毫秒)
|
||||||
|
this.cache.set(key, {
|
||||||
|
value,
|
||||||
|
expiresAt: Date.now() + ttl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
clearExpires() {
|
||||||
|
for (const [key, entry] of this.cache) {
|
||||||
|
if (entry.expiresAt < Date.now()) {
|
||||||
|
this.cache.delete(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -67,3 +67,8 @@ footer {
|
||||||
margin-inline-end: calc(-3em - 8px);
|
margin-inline-end: calc(-3em - 8px);
|
||||||
padding-inline-end: calc(3em + 8px);
|
padding-inline-end: calc(3em + 8px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ant-progress .ant-progress-text{
|
||||||
|
width:3em;
|
||||||
|
}
|
|
@ -47,6 +47,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
const { openSiteIpMonitorDialog } = useSiteIpMonitor();
|
const { openSiteIpMonitorDialog } = useSiteIpMonitor();
|
||||||
const { openSiteImportDialog } = useSiteImport();
|
const { openSiteImportDialog } = useSiteImport();
|
||||||
return {
|
return {
|
||||||
|
id: "siteMonitorCrud",
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
request: {
|
request: {
|
||||||
pageRequest,
|
pageRequest,
|
||||||
|
@ -117,7 +118,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
},
|
},
|
||||||
rowHandle: {
|
rowHandle: {
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
width: 240,
|
width: 280,
|
||||||
buttons: {
|
buttons: {
|
||||||
check: {
|
check: {
|
||||||
order: 0,
|
order: 0,
|
||||||
|
|
|
@ -45,6 +45,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
const { openSiteIpImportDialog } = useSiteIpMonitor();
|
const { openSiteIpImportDialog } = useSiteIpMonitor();
|
||||||
return {
|
return {
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
|
id: "siteIpCrud",
|
||||||
request: {
|
request: {
|
||||||
pageRequest,
|
pageRequest,
|
||||||
addRequest,
|
addRequest,
|
||||||
|
|
|
@ -17,12 +17,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="helper">{{ t("certd.monitor.setting.monitorRetryTimes") }}</div>
|
<div class="helper">{{ t("certd.monitor.setting.monitorRetryTimes") }}</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- <a-form-item :label="t('certd.monitor.setting.dnsServer')" :name="['dnsServer']">
|
<a-form-item :label="t('certd.monitor.setting.dnsServer')" :name="['dnsServer']">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<a-select v-model:value="formState.dnsServer" mode="tags" :open="false" />
|
<a-select v-model:value="formState.dnsServer" mode="tags" :open="false" />
|
||||||
</div>
|
</div>
|
||||||
<div class="helper">{{ t("certd.monitor.setting.dnsServerHelper") }}</div>
|
<div class="helper">{{ t("certd.monitor.setting.dnsServerHelper") }}</div>
|
||||||
</a-form-item> -->
|
</a-form-item>
|
||||||
<a-form-item :label="t('certd.monitor.setting.monitorCronSetting')" :name="['cron']">
|
<a-form-item :label="t('certd.monitor.setting.monitorCronSetting')" :name="['cron']">
|
||||||
<div class="flex flex-baseline">
|
<div class="flex flex-baseline">
|
||||||
<cron-editor v-model="formState.cron" :disabled="!settingsStore.isPlus" :allow-every-min="userStore.isAdmin" />
|
<cron-editor v-model="formState.cron" :disabled="!settingsStore.isPlus" :allow-every-min="userStore.isAdmin" />
|
||||||
|
|
|
@ -82,7 +82,6 @@
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"dns2": "^2.1.0",
|
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"glob": "^11.0.0",
|
"glob": "^11.0.0",
|
||||||
"https-proxy-agent": "^7.0.5",
|
"https-proxy-agent": "^7.0.5",
|
||||||
|
|
|
@ -27,6 +27,7 @@ export class UserSiteMonitorSetting extends BaseSettings {
|
||||||
notificationId?:number= 0;
|
notificationId?:number= 0;
|
||||||
cron?:string = undefined;
|
cron?:string = undefined;
|
||||||
retryTimes?:number = 3;
|
retryTimes?:number = 3;
|
||||||
|
dnsServer?:string[] = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UserEmailSetting extends BaseSettings {
|
export class UserEmailSetting extends BaseSettings {
|
||||||
|
|
|
@ -3,8 +3,13 @@ import { InjectEntityModel } from "@midwayjs/typeorm";
|
||||||
import { Repository } from "typeorm";
|
import { Repository } from "typeorm";
|
||||||
import { BaseService, BaseSettings } from "@certd/lib-server";
|
import { BaseService, BaseSettings } from "@certd/lib-server";
|
||||||
import { UserSettingsEntity } from "../entity/user-settings.js";
|
import { UserSettingsEntity } from "../entity/user-settings.js";
|
||||||
import { mergeUtils } from "@certd/basic";
|
import { LocalCache, mergeUtils } from "@certd/basic";
|
||||||
const {merge} = mergeUtils
|
const {merge} = mergeUtils
|
||||||
|
|
||||||
|
const UserSettingCache = new LocalCache({
|
||||||
|
clearInterval: 5 * 60 * 1000,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 授权
|
* 授权
|
||||||
*/
|
*/
|
||||||
|
@ -75,14 +80,26 @@ export class UserSettingsService extends BaseService<UserSettingsEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async getSetting<T>( userId: number,type: any): Promise<T> {
|
async getSetting<T>( userId: number,type: any, cache:boolean = false): Promise<T> {
|
||||||
if(!userId){
|
if(!userId){
|
||||||
throw new Error('userId is required');
|
throw new Error('userId is required');
|
||||||
}
|
}
|
||||||
const key = type.__key__;
|
const key = type.__key__;
|
||||||
|
const cacheKey = key + '_' + userId;
|
||||||
|
if (cache) {
|
||||||
|
const settings: T = UserSettingCache.get(cacheKey);
|
||||||
|
if (settings) {
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let newSetting: T = new type();
|
let newSetting: T = new type();
|
||||||
const savedSettings = await this.getSettingByKey(key, userId);
|
const savedSettings = await this.getSettingByKey(key, userId);
|
||||||
newSetting = merge(newSetting, savedSettings);
|
newSetting = merge(newSetting, savedSettings);
|
||||||
|
|
||||||
|
if (cache) {
|
||||||
|
UserSettingCache.set(cacheKey, newSetting);
|
||||||
|
}
|
||||||
return newSetting;
|
return newSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
import { LocalCache } from '@certd/basic';
|
||||||
|
import dnsSdk from 'dns'
|
||||||
|
const dns = dnsSdk.promises
|
||||||
|
|
||||||
|
export class DnsCustom{
|
||||||
|
resolver: any;
|
||||||
|
|
||||||
|
constructor(dnsServers:string[]) {
|
||||||
|
const resolver = new dns.Resolver();
|
||||||
|
resolver.setServers(dnsServers);
|
||||||
|
this.resolver = resolver;
|
||||||
|
}
|
||||||
|
async resolve(hostname:string,options:any):Promise<string[]>{
|
||||||
|
// { family: undefined, hints: 0, all: true }
|
||||||
|
|
||||||
|
const cnames = await this.resolver.resolveCname(hostname)
|
||||||
|
let cnameIps = []
|
||||||
|
// deep
|
||||||
|
if (cnames && cnames.length > 0) {
|
||||||
|
for (let cname of cnames) {
|
||||||
|
const cnameIp = await this.resolve(cname,options)
|
||||||
|
if (cnameIp && cnameIp.length > 0) {
|
||||||
|
cnameIps.push(...cnameIp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let v4 = []
|
||||||
|
let v6 = []
|
||||||
|
|
||||||
|
const {family, all} = options
|
||||||
|
if(family === 6 && !all){
|
||||||
|
v6= await this.resolver.resolve6(hostname)
|
||||||
|
}
|
||||||
|
if(family === 4 && !all){
|
||||||
|
v4 = await this.resolver.resolve4(hostname)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(all){
|
||||||
|
v4 = await this.resolver.resolve4(hostname)
|
||||||
|
v6 = await this.resolver.resolve6(hostname)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...v4,...v6,...cnameIps]
|
||||||
|
}
|
||||||
|
|
||||||
|
async resolve4(hostname:string,options:any):Promise<string[]>{
|
||||||
|
return await this.resolver.resolve4(hostname,options)
|
||||||
|
}
|
||||||
|
async resolve6(hostname:string,options:any):Promise<string[]>{
|
||||||
|
return await this.resolver.resolve6(hostname,options)
|
||||||
|
}
|
||||||
|
async resolveAny(hostname:string,options:any):Promise<string[]>{
|
||||||
|
return await this.resolver.resolveAny(hostname,options)
|
||||||
|
}
|
||||||
|
|
||||||
|
async resolveCname(hostname:string,options:any):Promise<string[]>{
|
||||||
|
return await this.resolver.resolveCname(hostname,options)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DnsContainer{
|
||||||
|
bucket: LocalCache<DnsCustom> = new LocalCache()
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
getDns(server:string[]){
|
||||||
|
const key = server.join(',')
|
||||||
|
let dns = this.bucket.get(key)
|
||||||
|
if (dns){
|
||||||
|
return dns
|
||||||
|
}
|
||||||
|
dns = new DnsCustom(server)
|
||||||
|
this.bucket.set(key,dns)
|
||||||
|
return dns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dnsContainer = new DnsContainer()
|
|
@ -15,6 +15,7 @@ import {UserSiteMonitorSetting} from "../../mine/service/models.js";
|
||||||
import {SiteIpService} from "./site-ip-service.js";
|
import {SiteIpService} from "./site-ip-service.js";
|
||||||
import {SiteIpEntity} from "../entity/site-ip.js";
|
import {SiteIpEntity} from "../entity/site-ip.js";
|
||||||
import {Cron} from "../../cron/cron.js";
|
import {Cron} from "../../cron/cron.js";
|
||||||
|
import { dnsContainer } from "./dns-custom.js";
|
||||||
|
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, {allowDowngrade: true})
|
@Scope(ScopeEnum.Request, {allowDowngrade: true})
|
||||||
|
@ -108,6 +109,14 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||||
if (!site?.domain) {
|
if (!site?.domain) {
|
||||||
throw new Error("站点域名不能为空");
|
throw new Error("站点域名不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(site.userId, UserSiteMonitorSetting);
|
||||||
|
const dnsServer = setting.dnsServer
|
||||||
|
let resolver = null
|
||||||
|
if (dnsServer && dnsServer.length > 0) {
|
||||||
|
resolver = dnsContainer.getDns(dnsServer) as any
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.update({
|
await this.update({
|
||||||
id: site.id,
|
id: site.id,
|
||||||
|
@ -117,7 +126,8 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||||
const res = await siteTester.test({
|
const res = await siteTester.test({
|
||||||
host: site.domain,
|
host: site.domain,
|
||||||
port: site.httpsPort,
|
port: site.httpsPort,
|
||||||
retryTimes
|
retryTimes,
|
||||||
|
resolver
|
||||||
});
|
});
|
||||||
|
|
||||||
const certi: PeerCertificate = res.certificate;
|
const certi: PeerCertificate = res.certificate;
|
||||||
|
|
|
@ -7,11 +7,15 @@ import {NotificationService} from "../../pipeline/service/notification-service.j
|
||||||
import {UserSuiteService} from "@certd/commercial-core";
|
import {UserSuiteService} from "@certd/commercial-core";
|
||||||
import {UserSettingsService} from "../../mine/service/user-settings-service.js";
|
import {UserSettingsService} from "../../mine/service/user-settings-service.js";
|
||||||
import {SiteIpEntity} from "../entity/site-ip.js";
|
import {SiteIpEntity} from "../entity/site-ip.js";
|
||||||
import dns from "dns";
|
import dnsSdk from "dns";
|
||||||
import {logger, safePromise} from "@certd/basic";
|
import {logger} from "@certd/basic";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import {siteTester} from "./site-tester.js";
|
import {siteTester} from "./site-tester.js";
|
||||||
import {PeerCertificate} from "tls";
|
import {PeerCertificate} from "tls";
|
||||||
|
import { UserSiteMonitorSetting } from "../../mine/service/models.js";
|
||||||
|
import { dnsContainer } from "./dns-custom.js";
|
||||||
|
|
||||||
|
const dns = dnsSdk.promises;
|
||||||
|
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
|
@ -62,11 +66,20 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||||
async sync(entity: SiteInfoEntity,check:boolean = true) {
|
async sync(entity: SiteInfoEntity,check:boolean = true) {
|
||||||
|
|
||||||
const domain = entity.domain;
|
const domain = entity.domain;
|
||||||
|
|
||||||
|
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(entity.userId, UserSiteMonitorSetting);
|
||||||
|
|
||||||
|
const dnsServer = setting.dnsServer
|
||||||
|
let resolver = dns
|
||||||
|
if (dnsServer && dnsServer.length > 0) {
|
||||||
|
resolver = dnsContainer.getDns(dnsServer) as any
|
||||||
|
}
|
||||||
|
|
||||||
//从域名解析中获取所有ip
|
//从域名解析中获取所有ip
|
||||||
const ips = await this.getAllIpsFromDomain(domain);
|
const ips = await this.getAllIpsFromDomain(domain,resolver);
|
||||||
if (ips.length === 0 ) {
|
if (ips.length === 0 ) {
|
||||||
logger.warn(`没有发现${domain}的IP`)
|
logger.warn(`没有发现${domain}的IP`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldIps = await this.repository.find({
|
const oldIps = await this.repository.find({
|
||||||
|
@ -86,7 +99,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||||
hasChanged = false
|
hasChanged = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hasChanged){
|
if(hasChanged){
|
||||||
logger.info(`发现${domain}的IP变化,需要更新,旧IP:${oldIps.map(ip=>ip.ipAddress).join(",")},新IP:${ips.join(",")}`)
|
logger.info(`发现${domain}的IP变化,需要更新,旧IP:${oldIps.map(ip=>ip.ipAddress).join(",")},新IP:${ips.join(",")}`)
|
||||||
//有变化需要更新
|
//有变化需要更新
|
||||||
|
@ -213,30 +226,26 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllIpsFromDomain(domain: string) {
|
async getAllIpsFromDomain(domain: string,resolver:any = dns):Promise<string[]> {
|
||||||
const getFromV4 = safePromise<string[]>((resolve, reject) => {
|
const getFromV4 = async ():Promise<string[]> => {
|
||||||
dns.resolve4(domain, (err, addresses) => {
|
try{
|
||||||
if (err) {
|
return await resolver.resolve4(domain);
|
||||||
logger.error(`[${domain}] resolve4 error`, err)
|
}catch (err) {
|
||||||
resolve([])
|
logger.error(`[${domain}] resolve4 error`, err)
|
||||||
return;
|
return []
|
||||||
}
|
}
|
||||||
resolve(addresses);
|
}
|
||||||
});
|
const getFromV6 = async ():Promise<string[]> => {
|
||||||
});
|
try{
|
||||||
|
return await resolver.resolve6(domain);
|
||||||
|
}catch (err) {
|
||||||
|
logger.error(`[${domain}] resolve6 error`, err)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getFromV6 = safePromise<string[]>((resolve, reject) => {
|
|
||||||
dns.resolve6(domain, (err, addresses) => {
|
|
||||||
if (err) {
|
|
||||||
logger.error("[${domain}] resolve6 error", err)
|
|
||||||
resolve([])
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(addresses);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all([getFromV4, getFromV6]).then(res => {
|
return Promise.all([getFromV4(), getFromV6()]).then(res => {
|
||||||
return [...res[0], ...res[1]];
|
return [...res[0], ...res[1]];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { logger, safePromise, utils } from "@certd/basic";
|
||||||
import { merge } from "lodash-es";
|
import { merge } from "lodash-es";
|
||||||
import https from "https";
|
import https from "https";
|
||||||
import { PeerCertificate } from "tls";
|
import { PeerCertificate } from "tls";
|
||||||
// import { TCPClient } from "dns2";
|
|
||||||
|
|
||||||
export type SiteTestReq = {
|
export type SiteTestReq = {
|
||||||
host: string; // 只用域名部分
|
host: string; // 只用域名部分
|
||||||
|
@ -11,7 +10,7 @@ export type SiteTestReq = {
|
||||||
retryTimes?: number;
|
retryTimes?: number;
|
||||||
ipAddress?: string;
|
ipAddress?: string;
|
||||||
|
|
||||||
dnsServer?: string[];
|
resolver?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SiteTestRes = {
|
export type SiteTestRes = {
|
||||||
|
@ -52,6 +51,7 @@ export class SiteTester {
|
||||||
req
|
req
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let customLookup = null
|
||||||
if (req.ipAddress) {
|
if (req.ipAddress) {
|
||||||
//使用固定的ip
|
//使用固定的ip
|
||||||
const ipAddress = req.ipAddress;
|
const ipAddress = req.ipAddress;
|
||||||
|
@ -61,37 +61,20 @@ export class SiteTester {
|
||||||
servername: options.host
|
servername: options.host
|
||||||
};
|
};
|
||||||
options.host = ipAddress;
|
options.host = ipAddress;
|
||||||
|
}else if (req.resolver ) {
|
||||||
|
// 非ip address 请求时
|
||||||
|
const resolver = req.resolver
|
||||||
|
customLookup = async (hostname:string, options:any, callback)=> {
|
||||||
|
console.log(hostname, options);
|
||||||
|
|
||||||
|
// { family: undefined, hints: 0, all: true }
|
||||||
|
const res = await resolver.resolve(hostname, options)
|
||||||
|
console.log("custom lookup res:",res)
|
||||||
|
callback(null, res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// let dnsClients = [];
|
options.agent = new https.Agent({ keepAlive: false, lookup: customLookup });
|
||||||
// if (req.dnsServer && req.dnsServer.length > 0) {
|
|
||||||
// for (let dns of req.dnsServer) {
|
|
||||||
// const dnsClient = TCPClient({ dns });
|
|
||||||
// dnsClients.push(dnsClient);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function customLookup(hostname, options, callback) {
|
|
||||||
// for (let client of dnsClients) {
|
|
||||||
// try {
|
|
||||||
// const result = await client.resolve(hostname, options);
|
|
||||||
// return callback(null, result);
|
|
||||||
// } catch (e) {
|
|
||||||
// this.logger.error(e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// try {
|
|
||||||
// // 使用自定义DNS解析
|
|
||||||
// const response = await dnsClients
|
|
||||||
// const address = response.answers[0].address;
|
|
||||||
// callback(null, address, 4);
|
|
||||||
// } catch (err) {
|
|
||||||
// // 解析失败时回退到系统DNS
|
|
||||||
// require('dns').lookup(hostname, options, callback);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
options.agent = new https.Agent({ keepAlive: false });
|
|
||||||
|
|
||||||
// 创建 HTTPS 请求
|
// 创建 HTTPS 请求
|
||||||
const requestPromise = safePromise((resolve, reject) => {
|
const requestPromise = safePromise((resolve, reject) => {
|
||||||
|
|
Loading…
Reference in New Issue