Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] not working at node 17 #705

Open
2 tasks done
davidmeirlevy opened this issue Feb 2, 2022 · 24 comments
Open
2 tasks done

[Bug] not working at node 17 #705

davidmeirlevy opened this issue Feb 2, 2022 · 24 comments
Labels

Comments

@davidmeirlevy
Copy link
Contributor

Checks

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
└── http-proxy-middleware@2.0.2

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

@davidmeirlevy
Copy link
Contributor Author

BTW, working great on node 16.x

@chimurai
Copy link
Owner

chimurai commented Feb 7, 2022

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.

@lydell
Copy link
Contributor

lydell commented Apr 14, 2022

This could be caused by: nodejs/node#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.

@treysis
Copy link

treysis commented Apr 14, 2022

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.

@krpeacock
Copy link

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.

Thank you, this was the issue for me on Node 17 and 18, while the pattern was working on previous node versions

@davidmeirlevy
Copy link
Contributor Author

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

@treysis
Copy link

treysis commented Apr 20, 2022

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

@chimurai
Copy link
Owner

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?

@lydell
Copy link
Contributor

lydell commented May 14, 2022

@chimurai I tested with Node.js 18.1.0 now, and yes, I have the same issue with Node.js 18.

@chimurai
Copy link
Owner

chimurai commented May 15, 2022

Looks like Node v17+ changed to way localhost is being looked-up:

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.

@treysis
Copy link

treysis commented May 15, 2022

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.

@raspy8766
Copy link

@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?

@davidmeirlevy
Copy link
Contributor Author

davidmeirlevy commented May 26, 2022

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

@chimurai
Copy link
Owner

Indeed not a bug in http-proxy-middleware but a configuration issue when upgrading to node 17/18.

@lydell
Copy link
Contributor

lydell commented May 26, 2022

@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: nodejs/node#40702 (comment)

@davidmeirlevy davidmeirlevy reopened this May 26, 2022
@chimurai
Copy link
Owner

Definitely makes sense to update the documentation with a note to new the Node behaviour in node 17+. 👍

@davidmeirlevy
Copy link
Contributor Author

@chimurai I created a PR for changing the docs accordingly:
#783

@pencilcheck
Copy link

pencilcheck commented Sep 14, 2022

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.

@theteladras
Copy link

This kind of bugs, have headache symptoms. 😄

@Chukwu3meka
Copy link

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 can't combine IP with subdomain

@treysis
Copy link

treysis commented Feb 14, 2023

@Chukwu3meka But localhost isn't a subdomain or what are you referring to?

@Chukwu3meka
Copy link

@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

@treysis
Copy link

treysis commented Feb 14, 2023

@Chukwu3meka I understand. Is there any reason for using subdomains of localhost?

Repository owner locked as resolved and limited conversation to collaborators Feb 14, 2023
@chimurai
Copy link
Owner

chimurai commented Feb 14, 2023

Please use the Discussions for project configuration issues. Thanks.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

9 participants