难以理解的node.js http抛出连接ECONNREFUSED(IPv6?)

时间:2013-03-05 15:06:56

标签: node.js ipv6 node.js-connect

我正在运行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) })

隐式和显式解析的URI都会引发错误,我得到以下两个输出:

  

错误:{[错误:连接ECONNREFUSED]     代码:'ECONNREFUSED',     错误:'ECONNREFUSED',     系统调用:'connect'}

主持人myhost.locallocalhost/etc/hosts的别名,是:

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

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

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然后手动获取网址工作正常,所以这不是一个奇怪的HTTP问题。
  3. 我使用node.js连接到其他主机没有问题,例如http://www.google.com
  4. 我希望有用的系统信息包括:

    $ 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
    

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

3 个答案:

答案 0 :(得分:9)

如果其他人遇到问题我会在这里发布。

Bert Belder,Node.js邮件列表:

  

在您的系统上,“myhost.local”解析为三个不同的地址   (127.0.0.1,:: 1和fe80 :: 1)。节点喜欢ipv4 over ipv6所以它会   尝试连接到127.0.0.1。 127.0.0.1:8080没有什么可以听的   connect()系统调用失败,ECONNREFUSED。节点不会重试   任何其他已解析的IP - 它只是向您报告错误。一个   简单的解决方案是用预期的替换'localhost'   目标IP地址,':: 1'。

     

这种行为是否正确对辩论有些开放,但是这一点   是它的原因。

     

伯特

答案 1 :(得分:3)

这源于Node的问题(虽然有办法解决它),按照discussion on 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包装器的第一个结果。

Contrast 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))]

答案 2 :(得分:0)

这有用吗?

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) 
});