Inexplicable node.js http抛出连接ECONNREFUSED(IPv6?)

我正在运行node.js,如下所示:

> http = require('http') > http.get('http://myhost.local:8080', function (res) { console.log("RES" + res) } ).on('error', function (e) { console.log("Error:", e) }) > uri = require('url').parse("http://myhost.local:8080") { protocol: 'http:', slashes: true, auth: null, host: 'myhost.local:8080', port: '8080', hostname: 'myhost.local', hash: null, search: null, query: null, pathname: '/', path: '/', href: 'http://myhost.local:8080/' } > http.get(uri, function (res) { console.log("RES" + res) } ).on('error', function (e) { console.log("Error:", e) }) 

隐式和显式parsing的URI都会抛出一个错误,我得到了以下输出:

错误:{[Error:connect ECONNREFUSED] code:'ECONNREFUSED',errno:'ECONNREFUSED',syscall:'connect'}

主机myhost.local/etc/hosts localhost的别名,具体如下:

 127.0.0.1 localhost myhost.local myhost 255.255.255.255 broadcasthost ::1 localhost myhost.local myhost fe80::1%lo0 localhost myhost.local myhost 

编辑 :我尝试了主机文件,包括最明显的每个排列:

 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost myhost.local myhost fe80::1%lo0 localhost 

编辑我也应该提到,我已经在多个Mac上试过了。

虽然这似乎是一个相当常见的错误,但我没有看到有用的解释或解决方法。 这里有一些值得注意的相关事实:

  1. 运行$ wget http://myhost.local:8080按预期工作,所以它不是防火墙问题。
  2. 运行$ telnet myhost.local 8080 ,然后手动GET'的url工作正常,所以这不是一个奇怪的HTTP问题。
  3. 使用node.js连接到其他主机,例如http://www.google.com,我毫不费力

我期望有用的系统信息将包括:

 $ node -v v0.9.11 $ uname -a Darwin myhost.local 12.2.1 Darwin Kernel Version 12.2.1: Thu Oct 18 12:13:47 PDT 2012; root:xnu-2050.20.9~1/RELEASE_X86_64 x86_64 $ sw_vers ProductName: Mac OS X ProductVersion: 10.8.2 BuildVersion: 12C3104 $ sudo netstat -nalt | grep LISTEN | grep 8080 tcp6 0 0 ::1.8080 *.* LISTEN 

有没有人知道这里发生了什么,可能会有什么修复?

我会在这里张贴这个以防其他人有这个问题。

Bert Belder,Node.js邮件列表:

在您的系统上,“myhost.local”parsing为三个不同的地址(127.0.0.1,:: 1和fe80 :: 1)。 节点比ipv6更喜欢ipv4,所以它会尝试连接到127.0.0.1。 在127.0.0.1:8080上没有任何内容正在监听,所以connect()系统调用失败,ECONNREFUSED。 节点不会重试任何其他parsing的IP – 它只是向您报告错误。 一个简单的解决scheme是用预期的目的IP地址':: 1'代替'localhost'。

这种行为是否正确有些争议,但是这是造成这种情况的原因。

伯特

这源于Node的一个问题(尽pipe有办法解决这个问题),正如在nodejs / Google Groups上的讨论一样,@ alessioalex在他的回答中提到了这个问题。 每个Bert Belder一个有用的评论:

应该有一个getaddrinfo包装器返回更多,只是第一个结果

例如,

 > require('dns').lookup('myhost.local', console.log) { oncomplete: [Function: onanswer] } > null '127.0.0.1' 4 

这是传递给Node的多个getaddrinfo结果中的第一个。 看来nodejs只使用getaddrinfo调用的第一项。 Bert和Ben Noordhuis在小组讨论中同意,应该有一种方法可以使getaddrinfo包装器返回更多的第一个结果。

对比python,它返回getaddrinfo所有结果:

 >>> import socket >>> socket.getaddrinfo("myhost.local", 8080) [(30, 2, 17, '', ('::1', 8080, 0, 0)), (30, 1, 6, '', ('::1', 8080, 0, 0)), (2, 2, 17, '', ('127.0.0.1', 8080)), (2, 1, 6, '', ('127.0.0.1', 8080)), (30, 2, 17, '', ('fe80::1%lo0', 8080, 0, 1)), (30, 1, 6, '', ('fe80::1%lo0', 8080, 0, 1))] 

这个工作吗?

 var http = require('http'); var options = { host: 'myhost.local', port: 8080, path: '/' }; http.get(options, function (res) { console.log("RES" + res) }).on('error', function (e) { console.log("Error:", e) });