### 穩定度: 2 - 穩定
通過`require('dns')`來獲取這個模塊。
這個模塊包含以下兩類函數:
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查找。除了`dns.lookup`外`DNS`模塊的所有函數都屬于這類。這類函數不與`dns.lookup`使用相同的配置文件。例如,它們不使用`/etc/hosts`配置文件。這類函數適合那些不希望使用底層操作系統工具來進行域名解析,總是想要執行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));
});
});
});
~~~
兩者之間的選擇會產生微妙的結果,更多信息請查詢下文`實現注意事項`章節。
#### dns.lookup(hostname[, options], callback)
解析`hostname`(如`'google.com'`)為第一個找到的A(IPv4)或AAAA(IPv6)記錄。`options`可以是對象或者數組。如果`options`沒有提供,那么IPv4和IPv6都是有效的。如果`options`是一個數組,那么它必須是`4`或`6`。
另外,`options`可以是一個含有以下屬性的對象:
- family: {Number} - 地址族。如果提供,必須為整數`4`或`6`。如果沒有提供,那么IPv4和IPv6都是有效的。
- hints: {Number} - 如果提供,它必須是一個或多個支持的`getaddrinfo`標識。如果沒有提供,那么沒有標識被傳遞給`getaddrinfo`。多個標識可以通過在邏輯上`ORing`它們的值,來傳遞給`hints`。支持的`getaddrinfo`標識請參閱下文。
- all: {Boolean} - 如果`true`,那么回調函數以數組的形式返回所有解析的地址,否則只返回一個地址。默認為`false`。
所有的屬性都是可選的,以下是一個`options`例子:
~~~
{
family: 4,
hints: dns.ADDRCONFIG | dns.V4MAPPED,
all: false
}
~~~
回調函數有參數(err, address, family)。`address`是IPv4或IPv6地址字符串。`family`是`adress`的協議族,即`4`或`6`。
如果`options`的所有參數都被設置,那么參數轉變為(err, addresses),`addresses`是一個地址和協議族數組。
若發生錯誤,`err`是錯誤對象,`err.code`是錯誤碼。不僅在`hostname`不存在時,在如沒有可用的文件描述符等情況下查找失敗,`err.code`也會被設置為`'ENOENT'`。
`dns.lookup`不需要與DNS協議有任何關系。它僅僅是一個連接名字和地址的操作系統功能。
在任何的`io.js`程序中,它的實現對表現有一些微妙但是重要的影響。在使用前,請花一些時間查閱`實現注意事項`章節。
#### dns.lookupService(address, port, callback)
解析給定的`address`和`port`為一個主機名和使用`getnameinfo`的服務。
回調函數有參數(err, hostname, service)。`hostname`和`service`參數是字符串(如分別為`'localhost'`和`'http'`)。
若發生錯誤,`err`是錯誤對象,`err.code`是錯誤碼。
#### dns.resolve(hostname[, rrtype], callback)
使用指定的`rrtype`類型,解析主機名(如`'google.com'`)為一個記錄數組。
有效的`rrtype`有:
- 'A' (IPV4 地址,默認)
- 'AAAA' (IPV6 地址)
- 'MX' (郵件交換記錄)
- 'TXT' (文本記錄)
- 'SRV' (SRV記錄)
- 'PTR' (用于IP反向查找)
- 'NS' (域名服務器記錄)
- 'CNAME' (別名記錄)
- 'SOA' (權限開始記錄)
回調函數有參數(err, addresses)。`address`中每個元素的類型由記錄類型所指定,并且在下文相應的查找方法中有描述。
若發生錯誤,`err`是錯誤對象,`err.code`是下文錯誤代碼列表中的一個。
#### dns.resolve4(hostname, callback)
與`dns.resolve()`相同,但只使用IPv4查詢(一個記錄)。地址是一個IPv4地址數組(如`['74.125.79.104', '74.125.79.105', '74.125.79.106']`)。
#### dns.resolve6(hostname, callback)
與`dns.resolve4()`相同,除了使用IPv6查詢(一個AAAA查詢)。
#### dns.resolveMx(hostname, callback)
與`dns.resolve()`相同,但是只用于郵件交換查詢(MX記錄)。
地址是一個MX記錄數組,每一個元素都有一個`priority`和一個`exchange`屬性(如`[{'priority': 10, 'exchange': 'mx.example.com'},...]`)。
#### dns.resolveTxt(hostname, callback)
與`dns.resolve()`相同,但是只用于文本查詢(TXT記錄)。地址是一個`hostname`可用的2-d數組(如`[ ['v=spf1 ip4:0.0.0.0 ', '~all' ] ]`)。每個字數組包含一個記錄的TXT數據塊。根據使用場景的不同,它們可能被連接在一起也可能被分開。
#### dns.resolveSrv(hostname, callback)
與`dns.resolve()`相同,但是只用于服務查詢(SRV記錄)。地址是一個`hostname`可用的SRV記錄數組。SRV記錄的屬性有`priority`,`weight`,`port`,和`name`(如`[{'priority': 10, 'weight': 5, 'port': 21223, 'name': 'service.example.com'}, ...]`)。
#### dns.resolveSoa(hostname, callback)
與`dns.resolve()`相同,但是只用于權限記錄查詢(SOA記錄)。
地址是一個有以下結構的對象:
~~~
{
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記錄)。地址是一個`hostname`可用的域名服務器記錄數組(如`['ns1.example.com', 'ns2.example.com']`)。
#### dns.resolveCname(hostname, callback)
與`dns.resolve()`相同,但是只用于別名記錄(別名記錄)。地址是一個`hostname`可用的別名數組(如`['bar.example.com']`)。
#### dns.reverse(ip, callback)
為得到一個主機名數組,反向查詢一個IP。
回調函數有參數(err, hostnames)。
若發生錯誤,`err`是錯誤對象,`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: 給定的提示標識非法。
- dns.NOTINITIALIZED: `c-ares`庫初始化未被執行。
- dns.LOADIPHLPAPI: 加載`iphlpapi.dll`錯誤。
- dns.ADDRGETNETWORKPARAMS: 找不到`GetNetworkParams`函數。
- dns.CANCELLED: DNS查詢被取消。
#### 支持的getaddrinfo標識
以下標識可以被傳遞給`dns.lookup`的`hints`:
- dns.ADDRCONFIG: 返回的地址類型由當前系統支持的地址類型決定。例如,如果當前系統至少有一個IPv4地址被配置,那么將只會返回IPv4地址。回溯地址不被考慮。
- dns.V4MAPPED: 如果IPv6協議族被指定,但是沒有發現IPv6地址,那么返回IPv6地址的IPv4映射。
### 實現注意事項
盡管`dns.lookup`和`dns.resolve*/dns.reverse`函數都用于關聯一個域名和一個地址(或反之亦然),它們的行為還是有些許區別。這些差別雖然微小,但是對于`io.js`程序的行為有重大影響。
#### dns.lookup
在引擎下,`dns.lookup`使用了和其他程序相同的操作系統功能。例如,`dns.lookup`將總是和`ping`命令一樣解析一個給定的域名。在大多類POSIX操作系統上,`dns.lookup`函數的表現可以通過改變`nsswitch.conf(5)` 和/或 `resolv.conf(5)`的設置來調整,但是需要小心的是,改變這些文件將會影響這個操作系統上正在運行的所有其他程序。
雖然在`JavaScript`的角度,這個調用是異步的,但是它在libuv線程池中的實現是同步調用`getaddrinfo(3)`。因為libuv線程池有一個固定的大小,意味著如果`getaddrinfo(3)`花費了太多的時間,那么其他libuv線程池中的操作(如文件系統操作)會感覺到性能下降。為了緩解這個情況,一個潛在的解決方案是通過設置`'UV_THREADPOOL_SIZE'`環境變量大于4(當前默認值)來增加libuv線程池的大小。更多libuv線程池的信息,請參閱官方的libuv文檔。
#### dns.resolve,以dns.resolve和dns.reverse開頭的函數
這些函數的實現與`dns.lookup`相當不同。它們不使用`getaddrinfo(3)`并且它們總是通過網絡執行一次DNS查詢。這些網絡通信通常是異步的,并且不使用libuv線程池。
作為結果,其他使用libuv線程池的`dns.lookup`方法的進程可能會有相同的負面影響,但這些函數沒有。
它們與`dns.lookup`使用了不同的配置文件。例如,它們不使用`/etc/hosts`中的配置。