http-proxy-middleware
http-proxy-middleware copied to clipboard
[Bug] not working at node 17
Checks
- [X] I understand project setup issues should be asked on StackOverflow or in GitHub Discussions.
- [X] I updated to latest
http-proxy-middleware
.
Describe the bug (be clear and concise)
use the library to proxy into another service. not working when upgraded to node 17.
Step-by-step reproduction instructions
1. using node 14.17 - works.
2. replace node 17.x - doesn't work.
console error:
[HPM] Error occurred while proxying request localhost:3000/aaa/ to http://localhost:3001/ [ECONNREFUSED]
### Expected behavior (be clear and concise)
proxy should work and return the data from another proxied service
### How is http-proxy-middleware used in your project?
```shell
└── [email protected]
What http-proxy-middleware configuration are you using?
{
target,
changeOrigin: true,
headers: {
tenant,
},
}
What OS/version and node/version are you seeing the problem?
System:
OS: macOS 12.1
CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Memory: 492.53 MB / 16.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 17.4.0 - ~/.nvm/versions/node/v17.4.0/bin/node
Yarn: 1.22.4 - /usr/local/bin/yarn
npm: 8.3.1 - ~/.nvm/versions/node/v17.4.0/bin/npm
Watchman: 2021.10.18.00 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.10.1 - /Users/XXX/.rvm/rubies/ruby-head/bin/pod
Homebrew: 3.3.9 - /usr/local/bin/brew
pip3: 21.2.4 - /usr/local/bin/pip3
RubyGems: 2.7.6 - /Users/XXX/.rvm/rubies/ruby-head/bin/gem
Utilities:
CMake: 3.16.4 - /usr/local/bin/cmake
Make: 3.81 - /usr/bin/make
GCC: 4.2.1 - /usr/bin/gcc
Git: 2.32.0 - /usr/bin/git
Clang: 13.0.0 - /usr/bin/clang
Servers:
Apache: 2.4.51 - /usr/sbin/apachectl
Virtualization:
Docker: 20.10.12 - /usr/local/bin/docker
SDKs:
iOS SDK:
Platforms: DriverKit 21.2, iOS 15.2, macOS 12.1, tvOS 15.2, watchOS 8.3
IDEs:
Nano: 2.0.6 - /usr/bin/nano
Vim: 8.2 - /usr/bin/vim
WebStorm: 2021.3.1
Xcode: 13.2.1/13C100 - /usr/bin/xcodebuild
Languages:
Bash: 3.2.57 - /bin/bash
Perl: 5.30.3 - /usr/bin/perl
Python: 2.7.18 - /usr/bin/python
Python3: 3.9.7 - /usr/local/bin/python3
Ruby: 2.6.0 - /Users/XXX/.rvm/rubies/ruby-head/bin/ruby
Databases:
MongoDB: 4.2.1 - /usr/local/bin/mongo
PostgreSQL: 14.0 - /usr/local/bin/postgres
SQLite: 3.36.0 - /usr/bin/sqlite3
Browsers:
Chrome: 97.0.4692.99
Firefox: 57.0.4
Safari: 15.2
Additional context (optional)
No response
BTW, working great on node 16.x
This example works in node v17.4.0.
https://github.com/chimurai/http-proxy-middleware/blob/master/examples/express/index.js
Just clone the repo and run node examples/express
from the project root folder.
Can you provide a minimal reproducible project with the error? Without one there is little to investigate.
This could be caused by: https://github.com/nodejs/node/issues/40702. I don’t understand the DNS stuff though, so I’m not sure about anything.
This seems to reproduce the problem:
app.use(
"/api",
proxy.createProxyMiddleware({
target: "http://localhost:3000",
})
);
I think the reason the linked example works is because it doesn’t use localhost
.
Note:
-
require("http").get("http://localhost:3000/", res => console.log(res.statusCode))
works on Node.js 16 but not 17 (ECONNREFUSED). -
curl -i http://localhost:3000
works.
EDIT: It seems like if I run the official Node.js HTTP hello world example on port 3000, require("http").get("http://localhost:3000/", res => console.log(res.statusCode))
works just fine. However, when I run a Suave server I run into ECONNREFUSED. So there’s something about what the server is doing as well. I have no reproduction going here.
EDIT2: Figured it out. I was running the Suave server explicitly on 0.0.0.0
, which is ipv4. Node.js uses ::
by default.
https://nodejs.org/api/net.html#serverlistenport-host-backlog-callback
If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise.
In most operating systems, listening to the unspecified IPv6 address (::) may cause the net.Server to also listen on the unspecified IPv4 address (0.0.0.0).
When setting host
to 0.0.0.0
I have a reproduction:
const http = require('http');
const requestListener = function (req, res) {
res.writeHead(200);
res.end('Hello, World!');
}
const server = http.createServer(requestListener);
server.listen(3000, '0.0.0.0');
Sorry, about the confusion – this is not my area of expertise.
You shouldn't be using localhost
but 127.0.0.1
instead. Reason is that name resolution for localhost varies a lot between different systems and implementations of their network stacks.
You shouldn't be using
localhost
but127.0.0.1
instead. Reason is that name resolution for localhost varies a lot between different systems and implementations of their network stacks.
Thank you, this was the issue for me on Node 17 and 18, while the pattern was working on previous node versions
@treysis that's weird, isn't it? every domain is something that is made up to locate a target IP somewhere for someone. doesn't matter if it's localhost or google.com. it's either configured in my hosts file, at the ISP, or ISOC.
@krpeacock Yes, that's why it was mentioned as a possibly breaking change and not introduced in 16, but in the short-term release 17, and also not backported to 16.
@davidmeirlevy
Kind of. I haven't figured out what's the differenc when opening a listening socket and when opening a socket for connecting. However, even if querying localhost returns both IPv4 and IPv6, the host OS/libraries still have a say in ordering the results. E.g. if a host or even just a single interface doesn't have IPv6 aside from the default link-local address, the system might decide that returning ::1
is not feasible and will still give precedence to 127.0.0.1
.
Support for node17 will stop in june 2022... Not sure if it worth the effort to investigate the issue for node 17.
Node 18 just got released: https://nodejs.org/en/blog/announcements/v18-release-announce/
Do you have the same issue when you're using node 18?
@chimurai I tested with Node.js 18.1.0 now, and yes, I have the same issue with Node.js 18.
Looks like Node v17+ changed to way localhost
is being looked-up:
- https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V17.md#17.0.0
- https://github.com/nodejs/node/issues/40537
- https://github.com/nodejs/node/pull/39793
- https://nodejs.org/docs/latest/api/cli.html#--dns-result-orderorder
Can you try replacing localhost
with 127.0.0.1
?
There is a --dns-result-order
flag which you can use to force old behaviour:
--dns-result-order=ipv4first
https://www.redhat.com/en/blog/welcome-nodejs-18
For dns lookups, Node.js no longer prefers IPv4 over IPV6. Instead, it will now respect the order that is returned based on the dns entries. For properly configured hosts this should not make a difference but if you have a partially or incorrectly configured IPv6 stack on your hosts you might start seeing problems that were hidden before. The command line option --dns-result-order=ipv4first can be used to revert to the old behavior if necessary.
Looks like Node v17+ changed to way
localhost
is being looked-up
Yes, partly. It just doesn't reorder the DNS results anymore. That's what we said all the time. The lookup works the same as before. Don't use the DNS flag as it will prevent IPv6-connectivity. Just instead of localhost use 127.0.0.1.
@chimurai the way we're using http-proxy-middleware
is through a node utility, so we can't dictate what domain/ip-address they use specifically. In the meantime we have this workaround/hack in place for users on Node 17+:
/**
* Workaround for http-proxy-middleware DNS lookup issue with Nodejs 17+
* [See here for details]{@link https://github.com/chimurai/http-proxy-middleware/issues/705#issuecomment-1126925635}
**/
target: target.replace('http://localhost', 'http://127.0.0.1'),
Any plans to fix this internally in the http-proxy-middleware
library?
@raspy8766 that's a neat solution
unfortunately for me, it won't work since I have a case with multi-tenancy, and there's a difference in dev between loading localhost
to 127.0.0.1
to 0.0.0.0
(the URLs in my system apply the relevant tenant to the system and act with different results).
but probably for most cases - your solution is excellent.
I think I will close this bug since it's actually a bug mostly in implementing dev environments with node, and not specifically for this middleware.
Indeed not a bug in http-proxy-middleware but a configuration issue when upgrading to node 17/18.
@chimurai Is it worth updating README.md (and examples) to use 127.0.0.1
instead of localhost
? And/or mention that one should probably proxy to 127.0.0.1
instead of localhost
etc? I’m thinking there are lots of people using this module during development, proxying to their API local server at localhost:1234
. Could save some time for people, and avoid unnecessary issues being opened. 🤷♂️
Tricky stuff, it’s all about whether the server I proxy to accepts IPv4, IPv6 or both.
Here are some more details: https://github.com/nodejs/node/issues/40702#issuecomment-1103623246
Definitely makes sense to update the documentation with a note to new the Node behaviour in node 17+. 👍
@chimurai I created a PR for changing the docs accordingly: https://github.com/chimurai/http-proxy-middleware/pull/783
for me, node 17 doesn't work because somehow the example code simply doesn't create the proxy from the right base url, it keeps using / to proxy for some reason. Using express, node 17, and used the example code provided.
The result is simply proxy didn't work. I guess I have to use another library, was expecting this work out of box but somehow it just doesn't work no matter what I do.
This kind of bugs, have headache symptoms. 😄
You shouldn't be using
localhost
but127.0.0.1
instead. Reason is that name resolution for localhost varies a lot between different systems and implementations of their network stacks.
You can't combine IP with subdomain
@Chukwu3meka But localhost
isn't a subdomain or what are you referring to?
@Chukwu3meka But
localhost
isn't a subdomain or what are you referring to?
Something like dev.127.0.0.1:3000 would not work, unlike dev.localhost:3000
@Chukwu3meka I understand. Is there any reason for using subdomains of localhost?
Please use the Discussions for project configuration issues. Thanks.