DNS
稳定性: 3 - 稳定
本节将介绍Node.js的DNS模块,你可以通过调用require('dns')
来访问DNS模块。
DNS模块包含的函数属于2个不同的分类:
1)使用系统底层的特性,完成名字解析,这个过程不需要网络通讯,这个分类仅有一个函数:dns.lookup
。开发者在同一个系统里名字解析都是用 dns.lookup
。
下面的例子解析了www.google.com
:
var dns = require('dns');
dns.lookup('www.google.com', function onLookup(err, addresses, family) {
console.log('addresses:', addresses);
});
2)连接到DNS服务器进行名字解析,始终使用网络来进行域名查询。这个分类包含除了dns.lookup
外的所有函数。这些函数不会和dns.lookup
使用同一套配置文件。如果你不想使用系统底层的特性来进行名字解析,而想进行DNS查询的话,可以使用这个分类的函数。
下面的例子,解析了'www.google.com'
,并反向解析返回的IP地址:
var dns = require('dns');
dns.resolve4('www.google.com', function (err, addresses) {
if (err) throw err;
console.log('addresses: ' + JSON.stringify(addresses));
addresses.forEach(function (a) {
dns.reverse(a, function (err, hostnames) {
if (err) {
throw err;
}
console.log('reverse for ' + a + ': ' + JSON.stringify(hostnames));
});
});
});
更多细节参考Implementation considerations section。
dns.lookup(hostname[, options], callback)
将域名(比如'google.com'
)解析为第一条找到的记录A (IPV4)或AAAA(IPV6)。参数options
可以是一个对象或整数。如果没有提供options
,IP v4和 v6地址都可以。如果options
是整数,则必须是4
或6
。
options
参数可能是包含family
和hints
两个属性的对象。这两个属性都是可选的。如果提供了family
,则必须是4
或6
,否则,IP v4和v6地址都可以。如果提供了hints
,可以是一个或者多个getaddrinfo
标志,若不提供,没有标志会传给getaddrinfo
。多个标志位可以通过或运算来整合。以下的例子展示如何使用options
。
{
family: 4,
hints: dns.ADDRCONFIG | dns.V4MAPPED
}
参见supported getaddrinfo
flags 查看更多的标志位。
回调函数包含参数 (err, address, family)
。address
参数表示IP v4或v6地址。family
参数是4或6,表示address
家族(不一定是之前传入lookup的值)。
出错时,参数err
是Error
对象,err.code
是错误代码。请记住,err.code
等于'ENOENT'
,不仅可能是因为域名不存在,还有可能是是其他原因,比如没有可用文件描述符。
dns.lookup
不必和DNS协议有关系。它使用了操作系统的特性,能将名字和地址关联。
实现这些东西也许很简单,但是对于 Node.js 程序来说都重要,所以在使用前请花点时间阅读Implementation considerations section。
dns.lookupService(address, port, callback)
使用getnameinfo
解析传入的地址和端口为域名和服务。
这个回调函数的参数是(err, hostname, service)
。hostname
和service
都是字符串 (比如'localhost'
和'http'
)。
出错时,参数err
是Error
对象,err.code
是错误代码。
dns.resolve(hostname[, rrtype], callback)
将一个域名(如'google.com')解析为一个rrtype指定记录类型的数组。
有效的rrtypes值为:
'A'
(IPV4地址,默认)
'AAAA'
(IPV6地址)
'MX'
(邮件交换记录)
'TXT'
(text记录)
'SRV'
(SRV记录)
'PTR'
(用来反向IP查找)
'NS'
(域名服务器记录)
'CNAME'
(别名记录)
'SOA'
(授权记录的初始值)
回调参数为(err, addresses)
. 其中addresses
中每一项的类型都取决于记录类型,详见下文对应的查找方法。
出错时,参数err
是 Error
对象,err.code
是错误代码。
dns.resolve4(hostname, callback)
和dns.resolve()
类似,仅能查询IPv4 (A
记录)。addresses
IPv4地址数组 (比如,['74.125.79.104', '74.125.79.105', '74.125.79.106']
)。
dns.resolve6(hostname, callback)
和dns.resolve4()
类似,仅能查询 IPv4(AAAA
查询)。
dns.resolveMx(hostname, callback)
和dns.resolve()
类似,仅能查询邮件交换(MX
记录)。
addresses
是MX记录数组,每一个包含优先级和交换属性(比如,[{'priority': 10, 'exchange': 'mx.example.com'},...]
)。
dns.resolveTxt(hostname, callback)
和dns.resolve()
类似,仅能进行文本查询 (TXT
记录)。addresses
是2-d文本记录数组。(比如,[ ['v=spf1 ip4:0.0.0.0 ', '~all' ] ]
)。每个子数组包含一条记录的TXT块。根据使用情况可以连接在一起,也可单独使用。
dns.resolveSrv(hostname, callback)
和dns.resolve()
类似,仅能进行服务记录查询 (SRV
记录)。addresses
是hostname
可用的SRV记录数组。SRV记录属性有优先级(priority),权重(weight), 端口(port), 和名字(name) (比如,[{'priority': 10, 'weight': 5, 'port': 21223, 'name': 'service.example.com'}, ...]
)。
dns.resolveSoa(hostname, callback)
和dns.resolve()
类似,仅能查询权威记录(SOA
记录)。
addresses
是包含以下结构的对象:
{
nsname: 'ns.example.com',
hostmaster: 'root.example.com',
serial: 2013101809,
refresh: 10000,
retry: 2400,
expire: 604800,
minttl: 3600
}
dns.resolveNs(hostname, callback)
和dns.resolve()
类似,仅能进行域名服务器记录查询(NS
记录)。addresses
是域名服务器记录数组(hostname
可以使用) (比如,['ns1.example.com', 'ns2.example.com']
)。
dns.resolveCname(hostname, callback)
和dns.resolve()
类似,仅能进行别名记录查询 (CNAME
记录)。addresses
是对hostname
可用的别名记录数组 (比如,['bar.example.com']
)。
dns.reverse(ip, callback)
反向解析IP地址,返回指向该IP地址的域名数组。
回调函数参数(err, hostnames)
。
出错时,参数err
是Error
对象,err.code
是错误代码。
dns.getServers()
返回一个用于当前解析的IP地址的数组的字符串。
dns.setServers(servers)
指定一组IP地址作为解析服务器。
如果你给地址指定了端口,端口会被忽略,因为底层库不支持。
传入无效参数,会抛出以下错误:
Error codes
每个DNS查询都可能返回以下错误:
dns.NODATA
: DNS服务器返回无数据应答。
dns.FORMERR
: DNS服务器声称查询格式错误。
dns.SERVFAIL
: DNS服务器返回一般失败。
dns.NOTFOUND
: 没有找到域名。
dns.NOTIMP
: DNS服务器未实现请求的操作。
dns.REFUSED
: DNS服务器拒绝查询。
dns.BADQUERY
: DNS查询格式错误。
dns.BADNAME
: 域名格式错误。
dns.BADFAMILY
: 地址协议不支持。
dns.BADRESP
: DNS回复格式错误。
dns.CONNREFUSED
: 无法连接到DNS服务器。
dns.TIMEOUT
: 连接DNS服务器超时。
dns.EOF
: 文件末端。
dns.FILE
: 读文件错误。
dns.NOMEM
: 内存溢出。
dns.DESTRUCTION
: 通道被摧毁。
dns.BADSTR
: 字符串格式错误。
dns.BADFLAGS
: 非法标识符。
dns.NONAME
: 所给主机不是数字。
dns.BADHINTS
: 非法HINTS标识符。
dns.NOTINITIALIZED
: c c-ares库尚未初始化。
dns.LOADIPHLPAPI
: 加载iphlpapi.dll出错。
dns.ADDRGETNETWORKPARAMS
: 无法找到GetNetworkParams函数。
dns.CANCELLED
: 取消DNS查询。
支持的 getaddrinfo 标志
以下内容可作为hints标志传给dns.lookup
dns.ADDRCONFIG
: 返回当前系统支持的地址类型。例如,如果当前系统至少配置了一个IPv4地址,则返回IPv4地址。
dns.V4MAPPED
: 如果指定了IPv6家族, 但是没有找到IPv6地址,将返回IPv4映射的IPv6地址。
Implementation considerations
虽然dns.lookup
和dns.resolve*/dns.reverse
函数都能实现网络名和网络地址的关联,但是他们的行为不太一样。这些不同点虽然很巧妙,但是会对Node.js程序产生显著的影响。
dns.lookup
dns.lookup
和绝大多数程序一样使用了相同的系统特性。例如,dns.lookup
和ping
命令用相同的方法解析了一个指定的名字。多数类似POSIX的系统,dns.lookup
函数可以通过改变nsswitch.conf(5)
和/或resolv.conf(5)
的设置调整。如果改变这些文件将会影响系统里的其他应用。
虽然,JavaScript调用是异步的,它的实现是同步的调用libuv线程池里的getaddrinfo(3)
。因为libuv线程池固定大小,所以如果调用getaddrinfo(3)
的时间太长,会使的池里的其他操作(比如文件操作)性能降低。为了降低这个风险,可以通过增加'UV_THREADPOOL_SIZE'的值,让它超过4,来调整libuv线程池大小,更多信息参见[the official libuvdocumentation](http://docs.libuv.org/en/latest/threadpool.html)。
dns.resolve, functions starting with dns.resolve and dns.reverse
这些函数的实现和dns.lookup
不大相同。他们不会用到getaddrinfo(3)
,而是始终进行网络查询。这些操作都是异步的,和libuv线程池无关。
因此,这些操作对于其他线程不会产生负面影响,这和dns.lookup
不同。
它们不会用到dns.lookup
的配置文件(例如 ,/etc/hosts
_)。