10

I'm getting some strange behaviour in Node when making a request to locally running server.

I have a local server listening on port 4000. When using node-fetch (or any other Node fetch implementation) I get an ECONNREFUSED error when making a request to it:

> fetch('http://localhost:4000')
Promise {
  <pending>,
  [Symbol(async_id_symbol)]: 345,
  [Symbol(trigger_async_id_symbol)]: 5
}
> Uncaught TypeError: fetch failed
    at Object.processResponse (node:internal/deps/undici/undici:5575:34)
    at node:internal/deps/undici/undici:5901:42 {
  cause: Error: connect ECONNREFUSED ::1:4000
      at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1195:16)
      at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) {
    errno: -61,
    code: 'ECONNREFUSED',
    syscall: 'connect',
    address: '::1',
    port: 4000
  }
}

I can happily make requests to this server using curl or a web browser without error (although it looks like it's trying IPv6 before IPv4):

$ curl localhost:4000 -v                                                                  
*   Trying ::1:4000...
* connect to ::1 port 4000 failed: Connection refused
*   Trying 127.0.0.1:4000...
* Connected to localhost (127.0.0.1) port 4000 (#0)
> GET / HTTP/1.1
> Host: localhost:4000
> User-Agent: curl/7.77.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< cache-control: max-age=0, private, must-revalidate
< content-length: 9
< content-type: text/plain; charset=utf-8
< date: Thu, 26 May 2022 10:01:52 GMT
< server: Cowboy
< x-request-id: FvKfbzxLnVk2GewAAE9B
<
* Connection #0 to host localhost left intact

If I use the IPv4 address directly in Node it seems to work:

> fetch('http://127.0.0.1:4000').then(r => console.log(r.status))
Promise {
  <pending>,
  [Symbol(async_id_symbol)]: 825,
  [Symbol(trigger_async_id_symbol)]: 799
}
> 200

Any ideas what's causing this and how to fix it?

Update:

As an experiment I disconnected from my local network and things work as normal once again. This leads me to think it's being caused by the manner of DNS resolution resulting from my network's dns config. But no idea why

harryg
  • 23,311
  • 45
  • 125
  • 198

2 Answers2

20

Put this somewhere in the beginning of your entry file:

import dns from 'node:dns';
dns.setDefaultResultOrder('ipv4first');
tech-escape
  • 369
  • 3
  • 7
2

Some versions of node seem to resolve DNS with IPv6 first, depending on your environment. When you set localhost, it tries to fetch the IPv6 address ::1 which may not be available.

You can force the DNS resolution order as suggested by tech-escape, setting a hardcoded IPv4 address (e.g. 127.0.0.1 instead of localhost) may also "fix" the issue

Open issue: https://github.com/nodejs/undici/issues/1602

Flo Schild
  • 5,104
  • 4
  • 40
  • 55
  • Could you tell more details about **depending on your environment**? – liuliang May 03 '23 at 12:31
  • I do not know the details of which node version resolves to ipv6 first, on which system, but I meant that from one version of node to another one, perhaps one platform to another, it may resolve to ipv4 first, or ipv6. – Flo Schild Jun 19 '23 at 21:49