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

时间:2022-12-28 13:07:22

I am running node.js as follows:

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

An error is thrown for both the implicit and explicitly parsed URI and I get the following output for both:

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

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

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

The host myhost.local is an alias for localhost in /etc/hosts, being:

主机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

EDIT: I tried virtually every permutation for the hosts file, including the most obvious:

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

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

EDIT I should also mention that I have tried this on more than one Mac now.

编辑我还应该提一下,我现在在多台Mac上试过这个。

Although it seems this is a rather common error, I have seen no useful explanations or workarounds. Here are some notable related facts:

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

  1. Running $ wget http://myhost.local:8080 works as expected, so it isn't a firewall problem.
  2. 运行$ wget http://myhost.local:8080按预期工作,因此它不是防火墙问题。

  3. Running $ telnet myhost.local 8080 and then manually GET'ing the url works fine, so it's not a weird HTTP problem.
  4. 运行$ telnet myhost.local 8080,然后手动获取url工作正常,所以这不是一个奇怪的HTTP问题。

  5. I have no trouble using node.js to connect to other hosts e.g. http://www.google.com
  6. 我使用node.js连接到其他主机没有问题,例如http://www.google.com

I expect the useful system information would include:

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

$ 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

Does anyone have any idea what is going on here, and what a fix might be?

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

3 个解决方案

#1


8  

I'm going to post this here in case somebody else has the problem.

我打算在这里发布,以防其他人有问题。

Bert Belder, Node.js mailing list:

Bert Belder,Node.js邮件列表:

On your system "myhost.local" resolves to three different addresses (127.0.0.1, ::1, and fe80::1). Node prefers ipv4 over ipv6 so it'll try to connect to 127.0.0.1. Nothing is listening on 127.0.0.1:8080 so the connect() syscall fails with ECONNREFUSED. Node doesn't retry with any of the other resolved IPs - it just reports the error to you. A simple solution would be to replace 'localhost' by the intended destination ip address, '::1'.

在您的系统上,“myhost.local”解析为三个不同的地址(127.0.0.1,:: 1和fe80 :: 1)。 Node优先选择ipv4而不是ipv6,因此它会尝试连接到127.0.0.1。在127.0.0.1:8080上没有任何内容正在侦听,因此connect()系统调用因ECONNREFUSED而失败。节点不会使用任何其他已解析的IP重试 - 它只会向您报告错误。一个简单的解决方案是将'localhost'替换为预期的目标IP地址':: 1'。

Whether this behavior is right is somewhat open for debate, but this is what causes it.

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

Bert

#2


3  

This stemmed from an issue with Node (though there are ways to work around it), as per the discussion on nodejs/Google Groups, as @alessioalex alluded in his answer. A useful comment per Bert Belder:

这源于Node的一个问题(虽然有办法解决它),根据对nodejs / Google Groups的讨论,正如@alessioalex在他的回答中提到的那样。每个Bert Belder都有用的评论:

there should be a getaddrinfo wrapper that returns more that just the first result

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

For example,

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

This is the first of multiple getaddrinfo results passed to Node. It seems that nodejs only uses the first item of the getaddrinfo call. Bert and Ben Noordhuis agreed in the Groups discussion that there should be a way to return more than just the first result with the getaddrinfo wrapper.

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

Contrast python, which returns all results from 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))]

#3


0  

does this work?

这有用吗?

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

#1


8  

I'm going to post this here in case somebody else has the problem.

我打算在这里发布,以防其他人有问题。

Bert Belder, Node.js mailing list:

Bert Belder,Node.js邮件列表:

On your system "myhost.local" resolves to three different addresses (127.0.0.1, ::1, and fe80::1). Node prefers ipv4 over ipv6 so it'll try to connect to 127.0.0.1. Nothing is listening on 127.0.0.1:8080 so the connect() syscall fails with ECONNREFUSED. Node doesn't retry with any of the other resolved IPs - it just reports the error to you. A simple solution would be to replace 'localhost' by the intended destination ip address, '::1'.

在您的系统上,“myhost.local”解析为三个不同的地址(127.0.0.1,:: 1和fe80 :: 1)。 Node优先选择ipv4而不是ipv6,因此它会尝试连接到127.0.0.1。在127.0.0.1:8080上没有任何内容正在侦听,因此connect()系统调用因ECONNREFUSED而失败。节点不会使用任何其他已解析的IP重试 - 它只会向您报告错误。一个简单的解决方案是将'localhost'替换为预期的目标IP地址':: 1'。

Whether this behavior is right is somewhat open for debate, but this is what causes it.

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

Bert

#2


3  

This stemmed from an issue with Node (though there are ways to work around it), as per the discussion on nodejs/Google Groups, as @alessioalex alluded in his answer. A useful comment per Bert Belder:

这源于Node的一个问题(虽然有办法解决它),根据对nodejs / Google Groups的讨论,正如@alessioalex在他的回答中提到的那样。每个Bert Belder都有用的评论:

there should be a getaddrinfo wrapper that returns more that just the first result

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

For example,

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

This is the first of multiple getaddrinfo results passed to Node. It seems that nodejs only uses the first item of the getaddrinfo call. Bert and Ben Noordhuis agreed in the Groups discussion that there should be a way to return more than just the first result with the getaddrinfo wrapper.

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

Contrast python, which returns all results from 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))]

#3


0  

does this work?

这有用吗?

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