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
Put this somewhere in the beginning of your entry file:
import dns from 'node:dns';
dns.setDefaultResultOrder('ipv4first');
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With