Node.js 16 -> 17 更改了“localhost”的解析?

Jas*_*n C 14 javascript sockets localhost node.js

在node.js 16.13.1(Windows)下,这样的代码可以工作(假设服务器存在并且工作正常):

import net from 'net';

let socket = net.createConnection({
    host: 'localhost',
    port: 12345
})
Run Code Online (Sandbox Code Playgroud)

更新到 node.js 17.7.2 后,上面的内容现在会抛出 ECONNREFUSED(连接被拒绝)错误。但是,它可以与“0.0.0.0”而不是“localhost”一起正常工作。

事实上,甚至记录的默认值“localhost”(感谢 VLAZ)在 17.7.2 上也失败了:

// connects with 16.13.1, ECONNREFUSED with 17.7.2:
net.createConnection({port:12345});

// connects with both versions:
net.createConnection({port:12345,host:'0.0.0.0'});

// connects with 16.13.1, ECONNREFUSED with 17.7.2:
net.createConnection({port:12345,host:'localhost'});
Run Code Online (Sandbox Code Playgroud)

我已经确认该行为取决于节点的版本。我可以通过使用建立网络连接的任何代码切换节点版本来可靠地避免/重现该行为。

我有相当多的代码,其主机默认为“localhost”。如果不需要的话,我宁愿不将所有这些更新为“0.0.0.0”。更乏味的是,用户通常提供主机地址并期望“localhost”能够工作,因此现在每次我使用用户指定的主机地址创建套接字时,我都必须添加将“localhost”转换为“0.0.0.0”的逻辑。我的意思是,我会做我必须做的事,但这很糟糕。

我的问题是:16.13.1 和 17.7.2 之间发生了什么导致“localhost”不再可用?这是一个错误,还是一些故意的改变?而且,有没有办法让它再次工作,或者我现在必须在各处查找+替换“localhost”为“0.0.0.0”?

我怀疑人们在互联网上询问的许多“连接拒绝本地主机”错误都与更改的内容有关......


更新:这似乎与 17 中接口枚举方式(或类似内容)的变化有关,而不是与“localhost”的具体使用有关。

例如,使用以下测试设置:

  • 使用节点创建三台 TCP 服务器:一台用于默认地址,一台显式设置“0.0.0.0”,一台显式设置“localhost”。
  • 三个客户端尝试连接到每台服务器,一个连接到默认主机,一个连接到“0.0.0.0”,一个连接到“localhost”。

然后使用 16.13.1:

默认收听 在 0.0.0.0 上收听 在本地主机上监听
连接到默认值 好的 好的 好的
连接到 0.0.0.0 好的 好的 好的
连接到本地主机 好的 好的 好的

但对于 17.7.2:

默认收听 在 0.0.0.0 上收听 在本地主机上监听
连接到默认值 好的 经济拒绝 好的
连接到 0.0.0.0 好的 好的 经济拒绝
连接到本地主机 好的 经济拒绝 好的

现在是使用节点创建的服务器;服务器和客户端的节点版本也相同。在我最初的情况下,我的服务器是使用 C++ 和标准socket()API 创建的,绑定到INADDR_ANY(0.0.0.0)。

测试代码:

import net from 'net';

console.log(process.version);

const accepted = detail => socket => socket.write(detail, ()=>socket.end());

const serversReady = () => [ 
    new Promise(resolve => net.createServer(accepted('default')).listen(12345, function(){resolve(this)})),
    new Promise(resolve => net.createServer(accepted('localhost')).listen(12346, 'localhost', function(){resolve(this)})),
    new Promise(resolve => net.createServer(accepted('0.0.0.0')).listen(12347, '0.0.0.0', function(){resolve(this)}))
];

const ports = [[12345,'default'], [12346,'localhost'], [12347,'0.0.0.0']];
const hosts = [{}, {host:'localhost'}, {host:'0.0.0.0'}];

const clientsDone = () => ports.map(([port,whichserver]) => hosts.map(host => new Promise((resolve, reject) => {
    let opts = {...host, port:port};
    net.createConnection(opts)
        .on('error', e => (console.log(opts, 'to:'+whichserver, 'error', e.message), reject(e)))
        .on('data', d => console.log(opts, 'to:'+whichserver, 'read', d.toString()))
        .on('end', () => resolve());
}))).flat();

Promise.all(serversReady())
    .then(servers => Promise.allSettled(clientsDone()).then(() => servers))
    .then(servers => servers.forEach(s => s.close()));
Run Code Online (Sandbox Code Playgroud)

下班后会对此进行更多讨论,但我想我应该早点发布这个而不是晚点。也会检查18。

shu*_*yan 5

我引用@richardlau的回答

Node.js 不再重新排序 IP 地址查找的结果并按原样返回它们(即它不再忽略操作系统的配置方式)。您可以通过 dns.lookup() 的逐字选项更改行为,或设置 --dns-result-order 命令行选项来更改默认值。

你可以尝试:

ping 本地主机

在你的cmd或终端中。如果显示:

127.0.0.1 的回复

这意味着您的系统更喜欢 ipv4 地址来解析localhost。如果显示:

回复者::1

这意味着您的系统更喜欢 ipv6 地址。

您可以更改系统设置以首选 ipv4。Node.js 将按照您的预期将localhost解析为 127.0.0.1。