Closed AlbinoGeek closed 4 years ago
Okay, so it's code-order dependant. You have to specify the CORS before any Subdomains or Party that might use it.
Also, I could not get specifying hosts to work, but putting a hard *
worked across the entire server.
@AlbinoGeek you have to specify what CORS middleware you used, because I can't see the import paths in the sample code, is it rs/cors, iris-contrib/middleware/cors? You can always just set the headers in WrapRouter
. WrapRouter should work because it runs before everything.
Examples:
I was using rs/cors
as per the example in this repository. It would appear that it can only be used app-wide, when really, it feels like this should be available at the subdomain level.
The fact that cors is order dependant has tripped me up three times today alone.
You have to use app.WrapRouter
after you have setup all your routes, else it doesn't work (only applies to ones specified before it's called.) While this is effectively a way to choose which routes it applies to, it is error-prone and not entirely intuitive given that the rest of iris
doesn't care what order you do things in (for the most part.)
You have to use app.WrapRouter after you have setup all your routes
That's strange, as app.WrapRouter
order does not matter. It has nothing to do with routes, it just wraps the main request handler (the router) and executes the logic itside it. The problem is that, the app.SubdomainRedirect
is a Wrapper too, so yes, you MUST register the cors wrapper last, so it can be executed first. It's not a bug... godocs:
https://github.com/kataras/iris/blob/ef7d365e8186394c4bc7af6565ffadc7d53006b1/iris.go#L142-L162
However, we can add debug messages to those wrappers, as we do with routes registration too. So you can see what wraps what if you ever come to this position again.
Note that, I think we can change the SubdomainRedirect
to be registered through the new app.UseRouter
instead of app.WrapRouter
, but this will have the same issues too, it should be registered first. What do you think abt?
Moreso, I feel there should be a cors
implementation that was a Use
middleware, (is that what the one in iris-contrib
does? and if so, it should probably the be the one shown in the _examples/
directory, instead of this one, which applies "all or nothing" in an error-prone way.)
Thank you for telling me about how WrapRouter
works. I did not realize Subdomain
was doing this. I thought it worked more like the Party
functions did, and added to the router's tree. (I had not looked in the source, but this is how gin
does it, where it doesn't matter what order you apply routes in, etc.)
@AlbinoGeek order of route registration does not matter in Iris too. The SubdomainRedirect
is a Wrapper not a route. You don't have to see the source code, I use VS Code and I can see the documentation(godoc) while typing the method name. As far as I know, gin
does not even has support for subdomain, so it doesn't even has a method to redirect from one subdomain to another, am I mistaken here?
As always, we must find a solution to that. We can make SubdomainRedirect
to be fired in a controlled way, no matter their call order. In order to do that, I want to know: you want subdomain redirect to be wrapped always on last so it's executed first or something else?
About the Use
, it's not possible to use CORS correctly that way because it decides before route match (e.g. method, url, host) and if you don't have a registered route with the specified http verb (e.g. OPTIONS | Party.AllowMethods(iris.MethodOptions) it will not do its job as expected. But you can use the UseRouter
or if you want for the entire website, WrapRouter
as you do now. The iris-contrib/middleware/cors
is the iris clone of rs/cors
. However, you have plenty of options for that.
Thank you for clarifying, and I may need to switch to vscode -- as Atom hasn't been autocompleting for Go for some time :( - rather a shame because I much prefer the extensibility of atom to a Microsoft product... but ehh, it's no longer working.
Thank you for explaining the situation as it is now. That would explain why CORS is the way it is at the moment, and that it really wouldn't be able to change considering the way it has to function, now I understand this.
When it comes to Subdomains and other Router Wrappers, I think there just needs to be a mention of it in their example, and that would probably suffice. I built most of my current application through the examples, referring to the documentation only when they fell short, and even then, it was more the godocs than iris-go (I really should have used the latter, but I honestly didn't know it was there until you mentioned it.)
What I've found at the moment is the most reliable way to use Subdomain
and SubdomainRedirect
is to define all your Subdomain
at the top of app initialization, then all your SubdomainRedirect
right at the end, and this seems to have the most consistent results.
gin
... you are correct. While there is a third-party vhost
module for it, this feature is not part of the core repository.
I think SubdomainRedirect
wrapping should be deferred until server setup personally, but there may be reasons not to do this? I'm just not thinking of them at the moment.
Such as the way that the initialization log only fires when the Runner starts, which is why I figured anything that I did to routing didn't matter until that point. (e.g: order agnostic.) Anything I logged up until that last call would end up behind the iris initialization log, so I figured the brunt of the work was being done then.
I'm going to nuke my atom
install and see if that fixes things. I think about the time Golang moved to modules, it stopped auto-completing, and I've just been coding "try and error" style ever since then as a matter of habit.
What I've found at the moment is the most reliable way to use Subdomain and SubdomainRedirect is to define all your Subdomain at the top of app initialization, then all your SubdomainRedirect right at the end, and this seems to have the most consistent results
OK, so subdomain redirect should always registered last (== executed first), even before CORS. That's easy to be controlled. Should I proceed with that change?
I think that would be the user's expectation, but I would ask others before doing so, in case they rely on the finite registration order of Subdomains
as things are at the moment. (Again, can't think of why you would, but it's possible, and I'd rather err on the side of caution when it comes to possibly breaking changes.)
gin... you are correct. While there is a third-party vhost module for it, this feature is not part of the core repository.
Still can't find that "vhost" module, I only saw one issue about subdomains and wildcard subdomains and the user is asking for subdomains support in Gin, like Iris does, 1 year ago. Can you give me a link? (If it's a net/http library, it is compatible with Iris so you don't need to use something you are not familiar with).
(Again, can't think of why you would, but it's possible, and I'd rather err on the side of caution when it comes to possibly breaking changes.)
I agree, that's why I didn't commit anything yet. I believe that the flow is normal as it's now but if that thing confused you it will confuse other developers too, so we must think of it, maybe it's just a documentation/example thing(but again, godocs explains how subdomain redirect work already)?
I stand corrected, you are right. This was specifically go-vhost
and gin
being hooked up together.
And you do have a point, I could serve assets under a different instance of iris
-- however, that then leads to a new question:
( My naive guess would be overriding logger.Config{logFunc}
)
Is there any way to differentiate the logs, such as applying a prefix, when using multiple instances of the logger?
Lol, that the thing I am working on it as we speak...and that's why I pushed a new release on https://github.com/kataras/golog some hours ago :D
EDIT: Oh if you mean about the request logger, yes you can custuomize its Logger per-instance already. I though you spoke about multiple application's loggers on places like sessions, mvc and e.t.c that they don't have direct access to the Iris Application (and its Logger instance which so far is golog.Default
and it's shared across all iris application instances of the same program)
And you do have a point, I could serve assets under a different instance of iris
Yes, be careful of the shared port though.
I stand corrected, you are right. This was specifically go-vhost and gin being hooked up together.
Yes go-vhost is not gin-specifically, it can be used with Iris but it has nothing to do with subdomain redirect, as far as I know, how did u manage to do dit with that library?
I'm glad you realized this issue (in regards to log prefixing!)
As per the request logger... I have other things to ask about it, but that will be in their own issues.
^ The shared port thing is why I was worried about multi-serving, and what was going to make me have to use nginx or something else in front of iris if it came to hosting multiple distinct application servers, something I am really trying to avoid having to do.
As per the vhost
thing, it was also kludgled together (yet, that site is still in production to this day without updates... have to love how traditional business never invests in maintaining systems until they stop working, it's always reactive and no proactive :(.) I'll see if I can dig that code up out of morbid curiosity.
I just remember I was fighting gin
s router to implement it.
I think I can close this issue now, since we're now talking about fixing the issue with a second iris instance.
^ The shared port thing is why I was worried about multi-serving, and what was going to make me have to use nginx or something else in front of iris if it came to hosting multiple distinct application servers, something I am really trying to avoid having to do.
@AlbinoGeek Here it's an alternative, if you think we must put something like as a builtn feature or let it as example please let me know:
package main
import (
"net/http"
"github.com/kataras/iris/v12"
)
func main() {
app := iris.New()
hosts := map[string]*iris.Application{
"mydomain.com": createRoot("www.mydomain.com"), // redirects to www.
"www.mydomain.com": createWWW(),
"test.mydomain.com": createTest(),
}
for _, r := range hosts {
r.Build()
}
app.Downgrade(func(w http.ResponseWriter, r *http.Request) {
host := r.Host
if host == "" {
host = r.URL.Host
}
if router, ok := hosts[host]; ok {
router.ServeHTTP(w, r)
return
}
http.NotFound(w, r)
})
app.Listen(":80")
}
func createRoot(redirectTo string) *iris.Application {
app := iris.New()
app.Downgrade(func(w http.ResponseWriter, r *http.Request) {
fullScheme := "http://"
if r.TLS != nil {
fullScheme = "https://"
}
http.Redirect(w, r, fullScheme+redirectTo+r.URL.RequestURI(), iris.StatusMovedPermanently)
})
return app
}
func createWWW() *iris.Application {
app := iris.New()
app.Get("/", index)
users := app.Party("/users")
users.Get("/", usersIndex)
users.Get("/login", getLogin)
return app
}
func createTest() *iris.Application {
app := iris.New()
app.Get("/", func(ctx iris.Context) {
ctx.WriteString("Test Index")
})
return app
}
func index(ctx iris.Context) {
ctx.Writef("This is the www.mydomain.com endpoint.")
}
func usersIndex(ctx iris.Context) {
ctx.Writef("This is the www.mydomain.com/users endpoint.")
}
func getLogin(ctx iris.Context) {
ctx.Writef("This is the www.mydomain.com/users/login endpoint.")
}
I think I can close this issue now, since we're now talking about fixing the issue with a second iris instance.
@AlbinoGeek You can re-open it. I can't leave an issue with the BUG label without a RESOLVED closed. We are not talking about second instance. The post says that there is a bug between cors and subdomains, I think we just be careful about order of registration on app.SubdomainRedirect
or just push them right before app.Listen
(recommended). So the question, is that a bug? It's not because it was expected.
Now, the question is: are we happy with the expected result?
I think the documentation on Subdomain
should be updated to advise the developer to place them just before their app.Listen
, so that it respects all the routes they have registered, or otherwise warns them that Subdomains
have to be registered before they plan to use something that uses WrapRouter
, like CORS
.
I would say that this is resolved, since CORS
does support Subdomains
, it just wasn't immediately obvious how that relationship worked, because other parts of iris
don't care about the order you register them in, but Subdomains
and WrapRouter
specifically do, and extra care has to be taken with them.
As per the second instance, I can't do this, because of my self-imposed TLS-behind-NAT hell, but that is a topic for another issue.
And again, thank you for all the effort you put forward to deal with people like me, hahaha. I really genuinely appreciate it. WIthout you, I would still be struggling through mixing together bits of gin
and other frameworks to get yet another duct-taped application server into the wild.
I think the documentation on Subdomain should be updated to advise the developer to place them just before their app.Listen
You mean SubdomainRedirect
, because Party.Subdomain
can be placed anywhere, the router builder sort routes by subdomains first (always), so order shouldn't matter, if it matters then it's a bug, are you sure?
And again, thank you for all the effort you put forward to deal with people like me, hahaha. I really genuinely appreciate it. WIthout you, I would still be struggling through mixing together bits of gin and other frameworks to get yet another duct-taped application server into the wild.
You are always welcomed @AlbinoGeek , we are just scratching the surface! There is always place for improvements, this is what I love about programming. Yes...lets not talk about other "frameworks" they are just routers :). Iris is a wise choice, not only because of its performance & features but also the almost real-time support and fixes you get, if you post an issue in any other repo you will get an answer after a lot of days (if you get any)... so I can totally feel you and that's why I am here.
I will follow your comments and update all subdomains examples with more comments, the godocs already contain enough information but will take look what can be improved over there too.
As per the second instance, I can't do this, because of my self-imposed TLS-behind-NAT hell, but that is a topic for another issue.
Look the code better, the application is running on :80
, the hosts thing is request-based so why not run behind NATS?
BTW: I am preparing a new function that can be declared anywhere and will accept a map ( so you have all the hosts redirection logic in one spot), it will act as a router specifically for subdomain/different domain across multiple Iris Application instances (that are not listening/running), in the end all that will be exposed to a single host:port.
Can't wait! Especially with how cumbersome this particular app I'm working on is already becoming, haha.
Summary
I attempted to host my assets directory as a Subdomain, which Chrome complained requires CORS. So, I followed the example code within the repository (which, btw, doesn't work on a
Party
, but only on the entire server, so is incompatible with subdomains), and found that it doesn't work at all.Screenshot
Versions, etc.
Sample Code