2013-03-05 2 views
4

Я бегу node.js следующим образом:Необъяснимые node.js HTTP метания подключения ECONNREFUSED (IPv6?)

> 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, и я получаю следующий результат для как:

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

хост myhost.local является псевдонимом для localhost в /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 

EDIT: Я попытался практически все перестановки в файле хостов, в том числе наиболее очевидным:

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

EDIT Я должен также упомянуть, что я попробовал это на более чем один Mac в настоящее время.

Хотя кажется, что это довольно распространенная ошибка, я не видел никаких полезных объяснений или обходных решений. Вот некоторые важные факты:

  1. Выполнение $ wget http://myhost.local:8080 работает должным образом, поэтому это не проблема межсетевого экрана.
  2. Запуск $ telnet myhost.local 8080, а затем вручную GET'ing 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 

Кто-нибудь есть какие-либо идеи, что происходит здесь, и что такое исправление может быть?

+0

Вы получаете ту же самую ошибку, если вы используете 'localhost' вместо' myhost.local'? – JohnnyHK

+0

Что-то работает на localhost: 80? – Floby

+0

@JohnnyHK, @Floby: приложение, к которому подключено приложение Google App Engine, привязано к 'myhost'. Позвольте мне опубликовать мой вывод «netstat», хотя, возможно, он освещает –

ответ

7

Я собираюсь опубликовать это здесь, если у кого-то еще есть проблема.

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'.

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

Bert

+0

Спасибо alessioalex. Извините, но я забыл упомянуть, что я пробовал каждую перестановку файла '/ etc/hosts', включая наличие только« :: localhost myhost.local ». Но безрезультатно. –

+0

Я должен отметить, что решение заключается в привязке сервера к IPv4, но это, конечно, неправильное решение. :) –

+0

«Узел предпочитает ipv4 над ipv6» - это, безусловно, неправильное поведение. См. [RFC 6724] (https://tools.ietf.org/html/rfc6724). –

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

Спасибо Manuel. Это фактически так же, как 'require ('url'). Parse (" http: //myhost.local: 8080/")', что и вызывает 'http.get', когда ему передается строка. Я уточнил свой вопрос, чтобы отразить это для ясности. –

3

Это вытекает из вопроса с узлом (хотя есть способы работать вокруг него), в соответствии с discussion on nodejs/Google Groups, как @alessioalex намекал в своем ответе , Полезный комментарий на Bert Белдером:

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

Например,

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

Это первый из нескольких getaddrinfo результатов, передаваемых в узел. Кажется, что nodejs использует только первый элемент вызова getaddrinfo. Берт и Бен Ноордхуис в обсуждении групп согласились, что должен быть способ вернуть больше, чем просто первый результат с оберткой getaddrinfo.

Contrast питон, который возвращает все результаты 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))] 
Смежные вопросы