expressjs / vhost

virtual domain hosting

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

vhost routes never get hit when ports are mentioned.

gaurav21r opened this issue · comments

On the heels of #10

app.use(vhost(localhost:8000), routes)
app.use(vhost(localhost:3000), routes)

window.fetch('http://localhost:8000/api/hello')
// Does not hit either!
// Because req.host is just localhost

This seems to be a problem in express's req.host and I've openned an issue here expressjs/express#3047

This module does not use req.host at all; it is not dependent on Express. We directly read the Host header: https://github.com/expressjs/vhost/blob/master/index.js#L77

Any issues with req.host cannot possibly be affecting this module. Can you provide full code and versions and how I can reproduce the issue?

@dougwilson Thank you for such a quick response 💯 👍 ! I'll try to push some code to a dummy repo so you can run it!

Oh, sorry, this is not a bug in anyway. You can see everywhere in the README, it says we are only routing on hostname, not host. This module does not in any way support port-based virtual hosts. This would have to be a feature you could make a PR to implement, though.

Oh Sorry it must've escaped me! We are stripping the port here https://github.com/expressjs/vhost/blob/master/index.js#L88 I really think this would be needed for local environments as we do not usually work with multiple domains but ports.

I'd love to submit a PR! But how should I go about doing it? According to me I can just modify the above lines but that would mean some unexpected changes for users.

I will need some time to refresh myself on how this module works before I can provide some direction. I should be able to get back to you on this within a week :)

In general, I would probably expect the syntax similar to that of Apache in some way: https://httpd.apache.org/docs/current/vhosts/examples.html

This would mean probably an optional :<port> at the end of the string, and of course you would need to account for the fact that IPv6 addresses have colons in them in your implementation.

Thanks @dougwilson Just to help you, the API is simple, as mentioned in README, its just vhost(hostname, handle)

Now users who were sending requests to http://doug.wilson.com:3000 are used to writing app.use(vhost(doug.wilson.com), route)
and I propose they should now write app.use(vhost(doug.wilson.com:3000)).

I can figure out the internals of vhost to send a PR. Could you just approve the right API from outside?

Btw I just did a Ctrl F on the README and couldn't find an explicit entry on ports. Maybe we could add it? :)

Following the example from Apache, is something like this fine?

A => window.fetch('http://doug.wilson.com:8000')
B => window.fetch('http://doug.wilson.com:3000')
C => window.fetch('http://doug.wilson.com')

app.use(vhost('doug.wilson.com:8000', route)) // Matches only A
app.use(vhost('doug.wilson.com:3000', route)) // Matches only B
app.use(vhost('doug.wilson.com', route)) // Matches A, B and C
app.use(vhost('doug.wilson.com:80', route)) // Matches only C

So the user has to explicitly declare a port within vhost to match it. Otherwise, its not breaking behaviour for current users just writing the domain without port. We can anyway bump up a version number to be sure.

I think Apache is also working this way!

Thanks for the heads up on the IPv6! I would have most certainly missed that 😛

The :80 example is not very good, because if you do that, then you'd also have to know if it was SSL or not, to determine if it should match against 80 or 443. Also, I just realized something: the Node.js server only lets you listen against a single port per server. If you are listening on multiple different ports, you had to have done that manually. Why would you not simply put up three different apps on the three different ports?

It's kind of complicated. You see we are emulating different environments in different ports. Since we have only one hostname localhost in the local dev environment. Now we are using an environment variable (which I believe is standard practice along with a config file) on the client side request part to control which environment we are requesting in.

The same environment variable is there on the server side. But when its on vhost() it gets ignored and no routes get hit.

Eg:

Client:
A => window.fetch('http://' + process.env.HOST)

Server:
app.use(vhost(process.env.HOST, route))

when process.env.HOST = 'localhost' everything is fine, but when its localhost:3000, vhost routes never get hit :(

Sure, but I would argue that, at least for that specific problem, it comes down to misunderstanding the documentation, and what a "hsotname" is vs a "host" (and defining that is really outside of the scope of this document, as they are general terms). If that was the summation of your problem, I would say that you should only provide the hostname as the first argument of the vhost factory, not the host :)

@dougwilson Our app (rather a platform for apps) gets a bit more complicated. In production we use proxying and I know that here we actually do have a problem bigger than documentation! What if these requests are coming from an nginx / node proxy and therefore multiple requests from diffrent ports all hitting the node server ona s ingle port but still have to be differentiated with vhost?

I know that nginx forwarding / load balancing is a fairly common use case in node?

Hi @gaurav21r, that is a good point, but I think that hasn't come up in the 5+ years of existence because having production differentiation on ports is very rare, compared to by hostnames, and even then, a feel like typically the edge node does the sharding to the backend, which doesn't seem to be the case in your example.

Hi @dougwilson, do you have any update on this? id really appreciate it!
Im too trying to use it with a port number, as i have to develop in localhost, and later ill use it with domains when in production.

@horaciogiovine was there something I was supposed to be doing in order to prove an update on something? From my remembering and re-reading this issue, @gaurav21r was maybe going to prove a PR if up to it. There is actually nothing left on this issue, so if you want to provide PR, @horaciogiovine please do!