Node.js API详解之 dns模块用法实例分析

本文实例讲述了Node.js API详解之 dns模块用法。分享给大家供大家参考,具体如下:

Node.js API详解之 dns

dns (域名服务器)模块包含两类函数:

第一类函数,使用底层操作系统工具进行域名解析,且无需进行网络通信。 这类函数只有一个:dns.lookup()。

例子,查找 baidu.com:

const dns = require('dns');
dns.lookup('www.baidu.com', (err, address, family) => {
 console.log('IP 地址: %j 地址族: IPv%s', address, family);
});
// IP 地址: "180.149.131.98" 地址族: IPv4

第二类函数,连接到一个真实的 DNS 服务器进行域名解析,且始终使用网络进行 DNS 查询。
这类函数包含了 dns 模块中除 dns.lookup() 以外的所有函数。
这些函数使用与 dns.lookup() 不同的配置文件(例如 /etc/hosts)。
这类函数适合于那些不想使用底层操作系统工具进行域名解析、而是想使用网络进行 DNS 查询的开发者。

例子,解析 ‘archive.org' 然后逆向解析返回的 IP 地址:

const dns = require('dns');
dns.resolve4('archive.org', (err, addresses) => {
 if (err) throw err;
 console.log(`IP 地址: ${JSON.stringify(addresses)}`);
 addresses.forEach((a) => {
  dns.reverse(a, (err, hostnames) => {
   if (err) {
    throw err;
   }
   console.log(`IP 地址 ${a} 逆向解析到域名: ${JSON.stringify(hostnames)}`);
  });
 });
});
// IP 地址: ["207.241.224.2"]
// IP 地址 207.241.224.2 逆向解析到域名: ["www.archive.org"]

dns.getServers()

说明:

返回一个用于当前DNF解析的IP地址的数组的字符串,格式根据rfc5952。
如果使用自定义端口,那么字符串将包括一个端口部分。

demo:

const dns= require('dns');
console.log( dns.getServers() );
// [ '172.116.20.254', '127.0.0.1' ]

dns.setServers(servers)

说明:

设置IP地址服务器端口在进行DNS解析时可用,servers参数是一个rfc5952数组格式的地址。
如果端口是IANA默认端口(53),那么它可以被忽略。

demo:

const dns = require('dns');
dns.setServers([ '172.116.20.254', '127.1.1.1' ])
console.log( dns.getServers() );
// [ '172.116.20.254', '127.1.1.1' ]

dns.lookup(hostname[, options], callback)

说明:

解析hostname(例如:'nodejs.org')第一个找到的A(IPv4)或AAAA(IPv6)记录。
options可以是对象或者整数。如果options没有被提供,那么IPv4 和 IPv6都是有效的。如果options是整数,只能是4或6。
另外,options可以是一个含有以下属性的对象:
family: T地址族。如果提供,必须为整数4或6。如果没有提供,只接受IPv4和IPv6地址。
all:值为true时, 回调函数返回一个包含所有解析后地址的数组,否则只返回一个地址。默认值为false
hints:如果提供,它必须是一个或多个支持的getaddrinfo标识。如果没有提供,那么没有标识被传递给getaddrinfo。
多个标识可以通过在逻辑上ORing它们的值,来传递给hints。支持的getaddrinfo标识:
dns.ADDRCONFIG: 返回当前系统支持的地址类型。例如,如果当前系统至少配置了一个 IPv4 地址,则返回 IPv4地址。不考虑回环地址。
dns.V4MAPPED: 如果指定了 IPv6 家族, 但是没有找到 IPv6 地址,将返回 IPv4 映射的 IPv6地址。在有些操作系统中不支持(e.g FreeBSD 10.1)。
回调函数包含(err, address, family)参数。
address是IPv4或IPv6地址字符串。
family、是整数4或6,表示地址族(不一定是最初传递给查找的值)。
当all属性被设置为true时,回调函数参数变为(err, addresses),addresses则变成一个由address 和 family 属性组成的对象数组。
dns.lookup() 不需要与DNS协议有任何关系。它仅仅是一个连接名字和地址的操作系统功能。
在任何的node.js程序中,它的实现对表现有一些微妙但是重要的影响。
尽管dns.lookup()和各种dns.resolve *()/ dns.reverse()函数有相同的目标将网络的名字与网络地址联系在一起(反之亦然),
他们的行为是完全不同的。 这些差异可以有微妙但重大影响着Node.js程序行为。

demo:

const dns = require('dns');
const options = {
  family: 6,
  hints: dns.ADDRCONFIG | dns.V4MAPPED,
};
dns.lookup('nodejs.cn', options, (err, address, family) =>
  console.log('address: %j family: IPv%s', address, family));
// address: "::ffff:112.124.39.54" family: IPv6
options.all = true;
dns.lookup('nodejs.cn', options, (err, addresses) =>
  console.log('addresses: %j', addresses));
// addresses: [{"address":"::ffff:112.124.39.54","family":6}]

dns.lookupService(address, port, callback)

说明:

将参数address和port传入操作系统底层getnameinfo服务来解析处理并返回主机名。
如果address不是有效的IP地址,会抛出TypeError。port必须是一个整数.如果不是规定的端口号,会抛出TypeError.
出错情况下,err是一个Error对象,err.code代码错误码。

demo:

const dns = require('dns');
dns.lookupService('127.0.0.1', 22, (err, hostname, service) => {
 console.log(hostname, service);
 // localhost ssh
});

dns.reverse(ip, callback)

说明:

执行一个反向DNS查询返回IPv4或IPv6地址的主机名的数组。

demo:

const dns = require('dns');
dns.reverse('101.20.17.16', (err, hostname) => {
 console.log(hostname);
});

dns.Resolver 类

说明:

DNS请求的独立解析程序。
使用默认的设置创建一个新的解析程序。
为一个解析程序设置servers使用resolver.setServers(),它不会影响其他的解析程序:

demo:

const { Resolver } = require('dns');
const resolver = new Resolver();
resolver.setServers(['4.4.4.4']);
resolver.resolve4('baidu.com', (err, addresses) => {
 console.log(addresses);
});

resolver.cancel()

说明:

取消这个解析程序的未解决的DNS查询,相应的回调用一个ECANCELLED码调用。

demo:

const { Resolver } = require('dns');
const resolver = new Resolver();
resolver.setServers(['4.4.4.4']);
resolver.resolve4('baidu.com', (err, addresses) => {
 console.log(addresses);
});
resolver.cancel();

dns.resolve(hostname[, rrtype], callback)

说明:

hostname:解析的主机名。
rrtype:资源记录类型. 默认: ‘A'.c
使用DNS协议来解析一个主机名(e.g. ‘nodejs.org')为一个资源记录的数组。
回调函数的参数为(err, records)。当成功时,records将是一个资源记录的数组。它的类型和结构取决于rrtype。
下面是不同rrtype对应resolve的快捷方法:

Node.js API详解之 dns模块用法实例分析

demo:

const dns = require('dns');
dns.resolve('archive.org', 'A', (err, addresses) => {
 if (err) throw err;
 console.log(`IP 地址: ${JSON.stringify(addresses)}`);
});
// IP 地址: ["207.241.224.2"]

dns.resolve4(hostname[, options], callback)

说明:

使用DNS协议解析IPv4地址主机名(A记录)。
adresses参数是传递给callback函数的IPv4地址数组。(例如:[‘74.125.79.104', ‘74.125.79.105', ‘74.125.79.106'])
hostname:需要解析的主机名
options.ttl:记录每一条记录的存活次数 (TTL)。如果为 true, 返回的结果将会为 Object 的数组,就像 { address: ‘1.2.3.4', ttl: 60 } 带有 TTL 秒数的记录,而不是 string 的数组.

demo:

const dns = require('dns');
dns.resolve4('archive.org', {ttl: true}, (err, addresses) => {
 if (err) throw err;
 console.log(`IPv4地址数组: ${JSON.stringify(addresses)}`);
});
// IPv4地址数组: [{"address":"207.241.224.2","ttl":58}]

dns.resolve6(hostname[, options], callback)

说明:

使用DNS协议解析IPv6地址主机名(AAAA记录)。
adresses参数是传递给callback函数的IPv6地址数组.

demo:

const dns = require('dns');
dns.resolve6('www.taobao.com', {ttl: true}, (err, addresses) => {
 if (err) throw err;
 console.log(`IPv6地址主机名: ${JSON.stringify(addresses)}`);
});
// IPv6地址主机名: []

dns.resolveCname(hostname, callback)

说明:

使用DNS协议解析CNAME记录主机名。
adresses参数是传递给callback函数规范内有效的主机名数组(例如:[‘bar.example.com']).

demo:

const dns = require('dns');
dns.resolveCname('www.taobao.com', (err, addresses) => {
 if (err) throw err;
 console.log(`CNAME记录主机名: ${JSON.stringify(addresses)}`);
});
// CNAME记录主机名: ["www.taobao.com.danuoyi.tbcache.com"]

dns.resolveMx(hostname, callback)

说明:

使用DNS协议处理邮件交换记录主机名(MX记录)。
adresses参数是传递给callback函数的主机名对象数组,对
象包含priority和exchange属性(例如: [{priority: 10, exchange: ‘mx.example.com'}, …])。

demo:

const dns = require('dns');
dns.resolveMx('mail.qq.com', (err, addresses) => {
 if (err) throw err;
 console.log(`MX记录: ${JSON.stringify(addresses)}`);
});

dns.resolveNaptr(hostname, callback)

说明:

使用DNS协议来处理基于正则表达式匹配的记录(NAPTR记录)的主机名。
adresses参数是传递给callback函数的主机名对象数组,对象包含属性:
flags
service
regexp
replacement
order
preference

demo:

const dns = require('dns');
dns.resolveNaptr('www.taobao.com', (err, addresses) => {
 if (err) throw err;
 
 console.log(`NAPTR记录: ${JSON.stringify(addresses)}`);
});

dns.resolveNs(hostname, callback)

说明:

使用DNS协议处理名称服务器主机名记录(NS记录)。
adresses为有效的名称服务器记录主机名数组(eg:[‘ns1.example.com', ‘ns2.example.com'])。

demo:

const dns = require('dns');
dns.resolveNs('www.taobao.com', (err, addresses) => {
 if (err) throw err;
 console.log(`NS记录: ${JSON.stringify(addresses)}`);
});

dns.resolvePtr(hostname, callback)

说明:

使用DNS协议处理主机名引用记录(PTR记录)。
addresses参数将一个字符串数组传递给回调函数callback,其中包含回复记录。

demo:

const dns = require('dns');
dns.resolvePtr('www.taobao.com', (err, addresses) => {
 if (err) throw err;
 
 console.log(`PTR记录: ${JSON.stringify(addresses)}`);
});

dns.resolveSoa(hostname, callback)

说明:

使用DNS协议处理主机名子域名记录(SOA记录)。addresses参数为一个对象包含以下属性:
nsname
hostmaster
serial
refresh
retry
expire
minttl

demo:

const dns = require('dns');
dns.resolveSoa('www.taobao.com', (err, addresses) => {
 if (err) throw err;
 
 console.log(`SOA记录: ${JSON.stringify(addresses)}`);
});

dns.resolveSrv(hostname, callback)

说明:

使用DNS协议来处理主机名服务记录(SRV记录)。
callback函数返回的addresses参数为对象数组,每个对象包含以下属性:
priority
weight
port
name

demo:

const dns = require('dns');
dns.resolveSrv('www.taobao.com', (err, addresses) => {
 if (err) throw err;
 console.log(`SRV记录: ${JSON.stringify(addresses)}`);
});

dns.resolveTxt(hostname, callback)

说明:

使用DNS协议处理文本查询主机名(TXT记录)。回调函数callback会返回records参数,
它是一个文本记录与主机名一一对应的二维数组(例如:[ [‘v=spf1 ip4:0.0.0.0 ‘, ‘~all' ] ]).
每个数组文本块包含一条记录。根据用例,这些可以是连接在一起或单独对待。

demo:

const dns = require('dns');
dns.resolveTxt('www.taobao.com', (err, addresses) => {
 if (err) throw err;
 
 console.log(`TXT记录: ${JSON.stringify(addresses)}`);
});

dns.resolveAny(hostname, callback)

说明:

使用DNS协议解析所有记录。
callback函数的参数将是一个包含各种类型记录的数组。每个对象都有一个属性type,指示当前记录的类型。
“A”、”AAAA”、”CNAME”、”MX”、”NAPTR”、”NS”、”PTR”、”SOA”、”SRV”、”TXT”等

demo:

const dns = require('dns');
dns.resolveAny('www.taobao.com', (err, addresses) => {
 if (err) throw err;
 console.log(`${JSON.stringify(addresses)}`);
});
// [ { type: 'A', address: '127.0.0.1', ttl: 299 },
//  { type: 'CNAME', value: 'example.com' },
//  { type: 'MX', exchange: 'alt4.aspmx.l.example.com', priority: 50 },
//  { type: 'NS', value: 'ns1.example.com' },
//  { type: 'TXT', entries: [ 'v=spf1 include:_spf.example.com ~all' ] },
//  { type: 'SOA',
//   nsname: 'ns1.example.com',
//   hostmaster: 'admin.example.com',
//   serial: 156696742,
//   refresh: 900,
//   retry: 900,
//   expire: 1800,
//   minttl: 60 } ]

错误码

说明:

每个DNS查询可以返回一个错误代码如下:
dns.NODATA:DNS服务返回没有数据。
dns.FORMERR:DNS服务器查询没有格式化。
dns.SERVFAIL:DNS服务器返回失败。
dns.NOTFOUND:域名未找到。
dns.NOIMP: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:指定非法的提示标志。
dns.NOTINITIALIZED:c-ares异步DNS请求库初始化未完成。
dns.LOADIPHLPAPI:加载iphlpapi.dll(Windows IP辅助API应用程序接口模块)错误
dns.ADDRGETNETWORKPARAMS:找不到GetNetworkParams(读取本机DNS信息)函数
dns.CANCELLED:DNS查询取消

dns.lookup() 与 dns.resolve(), dns.resolve*() and dns.reverse()

说明:

在底层,dns.lookup()使用操作系统设施与大多数其他程序相同。
例如,dns.lookup()几乎总是解析给定的主机名与ping命令一样。
在许多类POSIX操作系统中, dns.lookup()函数的行为可以通过改变nsswitch.conf(5)并且/或resolv.conf(5)设置进行改变,
但是需要注意改变这些文件就意味着改变所有正在这个操作系统中运行 的所有进程的行为。
尽管以异步JavaScript的角度来调用dns.lookup(),但在内部libuv底层线程池中却是同步的调用getaddrinfo(3)
dns.resolve(), dns.resolve*() and dns.reverse()这些功能实现与dns.lookup()截然不同。
它们不仅没有使用getaddrinfo(3)并且通过网络执行DNS查询。使用异步网络通信,并且没有使用libuv线程池。
因此,这些函数不会像使用libuv线程池的dns.lookup()函数一样会对其它进程有负面影响。
它们不像dns.lookup()一样使用相同的配置文件。例如,它们不会使用来自/etc/hosts配置。

希望本文所述对大家node.js程序设计有所帮助。