作为 Node.js 的内置模块之一,dns 模块日常的使用率并不高。但在某些情况下 dns 模块却是非常有用的,例如在需要通过 Node.js 来判断本地网络是否畅通;或者在某些高并发的情况下,可以手动通过 dns 模块进行查询并缓存之后,再进行请求发送。
所以 dns 模块还是有必要好好了解了解的,毕竟说不定什么时候就用上了呢?
解析
作为一个合格的 dns 模块,必然是需要具备 DNS 解析的功能了。在 dns 模块中,用于解析的函数分为两种,一种是通过使用底层操作系统工具进行本地域名解析,且无需进行网络通信。而另一个则是通过连接 DNS 服务器进行域名解析。
本地解析
本地解析顾名思义就是不进行网络请求来进行解析,一般用来查看本地请求某个域名时,对应的 IP 地址是什么。dns 模块中通过 dns.lookup()
方法来进行本地域名解析,解析的过程类似于 ping
。
dns.lookup(hostname[, options], callback)
const dns = require('dns');
dns.lookup('ahonn.me', (err, address, family) => {
if (err) {
throw err;
}
console.log('address: %s, family: IPv%s', address, family);
});
// address: 151.101.100.133, family: IPv4
可以通过函数的第二个参数 options 来进行解析的设置,例如能够传入 { all: true }
,来获取所有的解析结果(包括 IPv4 与 IPv6)。
网络解析
除了 dns.lookup()
之外,dns 模块中的其他函数都是通过网络进行 DNS 解析。其中最主要的一个方法就是: dsn.resolve()
。
dns.resolve(hostname[, rrtype], callback)
const dns = require('dns');
dns.resolve('ahonn.me', (err, records) => {
if (err) {
throw err;
}
console.log(records);
});
// [ '151.101.100.133' ]
该方法通过二个参数可以指定解析的资源记录类型,默认为 ’A’,即返回 IPv4 地址。如果想返回所有的资源纪录类型的值,可以通过 dns.resolveAny()
来获取。
dns.resolveAny(hostname, callback)
const dns = require('dns');
dns.resolveAny('ahonn.me', (err, records) => {
if (err) {
throw err;
}
console.log(records);
});
/* [ { address: '151.101.100.133', ttl: 369, type: 'A' },
{ value: 'dns10.hichina.com', type: 'NS' },
{ value: 'dns9.hichina.com', type: 'NS' },
{ entries:
[ 'google-site-verification=j5dWC85DkoAfUR50W00ewfii3X9ouH55HnyBP6oZxGE' ],
type: 'TXT' },
{ nsname: 'dns9.hichina.com',
hostmaster: 'hostmaster.hichina.com',
serial: 2015090709,
refresh: 3600,
retry: 1200,
expire: 3600,
minttl: 360,
type: 'SOA' }] */
与此同时,模块还提供了一些与资源记录类型绑定的函数,用于单独获取某资源记录类型的值。例如 dns.resolve4()
,dns.resolve6()
与dns.resolveCname()
等。
反向解析
一般情况下我们所说的 DNS 解析指的是正向解析,即通过域名查询 IP 地址。那么既然有正向解析就必然有反向解析了(rDNS)。dns 模块中同样提供了方法来进行反向查询,通过 IP 地址查找对应的域名。
dns.reverse(ip, callback)
dns.resolve('google.com', (err, addresses) => {
if (err) {
throw err;
}
addresses.map(ip => {
dns.reverse(ip, (err, hostnames) => {
if (err) {
throw err;
}
console.log(ip, hostnames);
});
})
});
TIPS: 在命令行中我们可以通过
nslookup -qt=ptr <IP>
来查看该 IP 地址反向解析的结果信息。
还需要注意的是大多数 IP 地址都没有做反向域名解析,设置反向解析需要找对应的服务器 IP 提供商进行设置。如何为服务器 IP 地址添加反向解析可参考这篇文章:为服务器IP添加反向DNS解析 | 祁劲松的博客👨💻。
反向解析主要应用到邮件服务器中来阻拦垃圾邮件,若邮件发送者的 IP 地址没有设置反向解析则将其视为垃圾邮件。
设置 DNS 服务器
默认情况下 DNS 服务器的 IP 地址是由网关进行分配的,但我们也可以设置为我们想使用的 IP 地址。比较有名的是国内通用的 114.114.114.114 以及 Google 的 8.8.8.8。
dns.setServers(servers)
Dns 模块可以通过 dns.setServers()来设置模块使用哪些 DNS 服务器进行解析。例如我们将 dns 模块使用的 DNS 服务器设置为 8.8.8.8。
const dns = require('dns');
dns.setServers(['8.8.8.8']);
dns.resolove('ahonn.me', (err, records) => {
if (err) {
throw err;
}
console.log(records);
});
dns.Resolver()
另外我们也可以通过 dns.Resolver()进行独立的设置 DNS 服务器 IP 地址,这样就不会影响 dns 模块的默认 DNS 服务器配置。 dns.Resolver() 的实例拥有与 dns 模块相同的 lookup, resolve等方法。
const { Resolver } = require('dns');
const resolver = new Resolver();
resolver.setServers(['8.8.8.8']);
reslover.reslove('ahonn.me', (err, records) => {
if (err) {
throw err;
}
console.log(records);
});
通过 dns 模块中的反向解析可以判断是否为垃圾邮件之外,正向解析可以定时向指定的 DNS 服务发送请求进行 DNS 解析,用来确认当前是否连接到网络(网络断开的情况下必然是没有办法通过网络进行 DNS 解析)。
const { Resolver } = require('dns');
function internetAvailable() {
const resolver = new Resolver();
resolver.setServers(['8.8.8.8']);
reslover.reslove('google.com', (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
}