Node.js 从列表中查找最快的 HTTP/2 DoH 服务器
对 DoH(DNS over HTTPS)来说 HTTP/2 尤其有效,因为 HTTP/2 支持多路复用,允许在同一连接上发送多个 DNS 查询,而无需等待之前的响应。这可以大大提高 DNS 解析的性能,尤其是在同时进行多个查询时。
网络上有数百个公开可用的 DoH 服务器,我们可以使用 Node.js HTTP/2 模块来查找在一定阈值(如 1 秒)内响应最快的服务器。
首先,让我们定义一个函数 check_url
,它将返回一个 promise,并在 HTTP/2 请求成功时转为 resolve 状态。
const http2 = require('http2');
const timeoutDuration = 1000; // 1 seconds
function check_url(URL) {
let fnResolve, fnReject;
let myPromise = new Promise((resolve, reject) => {
fnResolve = resolve;
fnReject = reject;
});
const client = http2.connect(URL);//https://dns.alidns.com , https://dns.quad9.net
const req = client.request({ ':path': '/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' });
req.on('response', (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
fnResolve(' ' + URL);
});
return myPromise;
}
让我们添加一些处理逻辑,当错误或超时发生时将 promise 转为 reject 状态。
req.on('error', (err) => {
console.error('ClientHttp2Stream error: ' + err);
req.close(http2.constants.NGHTTP2_CANCEL);
fnReject('!!! ' + URL)
});
// Set a timeout on the request
req.setTimeout(timeoutDuration, () => {
console.error(`ClientHttp2Stream ${URL} timed out`);
req.destroy();
fnReject('--- ' + URL)
});
最后,添加一个处理函数,在请求流完成并关闭时同时关闭 HTTP/2 连接(请记住,HTTP/2 允许在同一连接上进行多个并发流,因此连接不会自动关闭)。
req.on('close', (e) => {
console.log( 'ClientHttp2Stream is closed' )
client.close();
})
现在,我们可以使用递归函数逐个检查列表中的 url,并返回响应时间在 1 秒以内的最快服务器。
let dohs = ["https://dns.google/dns-query",
"https://cloudflare-dns.com/dns-query",
"https://dns.alidns.com/dns-query",
"https://dns.quad9.net/dns-query"];
/*
* check_next check doh[index], then doh[++index]...
* show:
* 0 show urls response within timeoutDuration
* 1 show urls response great than timeoutDuration
* 2 don't show urls, for debug
*/
function check_next(index = 0, { show = 0 } = {}) {
if (index >= dohs.length || index < 0) return;
check_url(dohs[index])
.then(URL => { if (0 === show) console.log(URL) })
.catch(error => { if (1 === show) console.log(error) })
.finally(() => {
//only check_next when last check is done
check_next(++index, { show })
});
}
check_next(0, { show: 0 })
运行 Node 代码,获取最快服务器列表
node find-fastest-doh-servers.js
# 输出结果
# https://dns.alidns.com/dns-query
# https://dns.quad9.net/dns-query
完整代码在 GitHub Gist 上面
https://gist.github.com/likev/7c26cec0103b3187ddcb793f94ae593c