-
Notifications
You must be signed in to change notification settings - Fork 38.5k
X-Fowarded-Prefix value replacing the context path while generating link using spring HATEOAS #31241
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
Comments
There is no way currently to prepend instead of replace. Does |
That seems like a bug to me. In what circumstances would you expect context path not to be included in the request URI? The responsible code is in public String getContextPath() {
return (this.forwardedPrefix != null ? this.forwardedPrefix : this.delegate.get().getContextPath());
} So it explicitly drops the context path if a |
Another more recent discussion, under #27739 with a concrete scenario. Not sure if we need to make this configurable but it's been working this way for a very long time now. I don't think we can just flip the behavior. |
It looks like I agree with past me - the discussion in #18842 didn't make any sense back then and it still doesn't. I gave up back then because no context path is normal for Spring Boot, so I didn't expect to encounter the bug very often. The proxy is not relevant, to the use case in this issue anyway. It is the local app that has a context path (for whatever reason - I agree with you that it doesn't need to have one, but if it does then this bug shows up). IMO it's still a bug, until I hear from someone who actually uses a context path and needs the links to be wrong. |
I just chatted with @rwinch and he had a use case where omitting the context path was necessary (but still screwy if you ask me). He wanted the proxy to map requests to https://app.example.com/{path} to http://localhost:8080/app/{path}, where "/app" is now the context path, and therefore for links to come back with the context path stripped the proxy passes "X-Forwarded-Prefix: " (empty). IMHO this is still crazy because there is nothing special about a context path for the proxy, which can know nothing of the implementation details of the backend. If it wasn't for the servlet spec we wouldn't even have the notion of a context path, and the proxy has no business assuming that the backend is built using servlets or Spring. But I concede that in this case at least passing an empty (not null) prefix is the only way to signal that you want something deleted from the link addresses. The problem is that we don't have a way for a proxy to ask for a path segment to be deleted. For the sake of clarity, my intuition for this header is that the proxy is telling you about a prefix that it has removed. So a gateway where https://example.com/app/{path} is mapped to http://localhost:8080/{path} sends a header value "/app". This seems far more regular, and is a less crazy setup than assuming the proxy somehow knows about context paths. That's the problem with the current implementation - in my example the proxy has to send "/app/context-path" as the prefix header, even though it only stripped the first segment. My advice for anyone who encounters this bug (including future me): don't use a context path in your Spring Boot applications. It's much simpler for everyone. |
@dsyer, How can we force someone not to use context path? This is our use case.
Now in this scenario, we need From the discussion threads you shared I agree with idea that ForwardedHeaderFilter should have contextPathOverride property. But seems in current implementation it's missing. |
Until something changes you have 2 options: write your own filter or remove the context path. The context path really isn't necessary in a Boot application (it's kind of an artifact of the old application server deployment model), so all you need to do is add your prefix to all the |
Prefix as a Noun (Replace) vs Verb (Inserting)I think the confusion comes from the fact that the word prefix is both a noun (how An ExampleThe prefix is identified as the portion of the URL prior to the capture group. A concrete example can help to make this more clear. Consider the mapping of
The prefix of the proxy is Proxy and Context Path?While a context path is a Java specific construct, the idea of a base path is not. For example, Ruby allows specifying a relative_url_root which is similar to a context path. In the example above, there is nothing Java specific that the proxy needs to understand. The proxy only needs to understand how it is routing the requests (which it must know already). This allows a Java application to adjust it's context root (base path or prefix), a Ruby application to adjust its A Use Case@dsyer mentioned our discussion, but I think some additional context could be beneficial. A use case that I see frequently is that an organization pays licenses per production application server. This means that they prefer to deploy multiple applications to each application server to avoid paying the licensing fees. I also see organizations that are using more resource intensive application servers. This means that they prefer to deploy multiple applications to each application server to avoid consuming additional resources. In both of these use cases, applications must define a non-empty context root because there is more than one application associated to the same application server. While their application is deployed with a non-empty context root, they do not want this expressed in the path of their URLs because they use a different subdomain for each application. Using different subdomains for each application provides benefits such as:
In this scenario, the organization's wish to have a mapping of
Benefits to Replacing the PrefixAs Spring’s In general, if How to Configure
|
Thanks for detailed explanation Rob. I will try to use your suggestions to fix my issue. One suggestion is that, the word prefix creates lot of confusion, if possible we should consider renaming this word that better reflects the actual implementation (Replace). And doesn't creates noun vs verb mess. Something like X-Forwarded-Root-Path. Just a suggestion. We can close this ticket. |
I would actually rather not close it again without making a change to the filter. IMO the default behaviour is wrong, but at least we could provide a flag for users to switch to include the context path. |
Agree with you Dave. If we can do this, it will be great. For me having 'contextPathOverride' property in filter makes sense. |
I've added a couple more sections to my original post (so all of the information can be easily found) to address the comments since my post. The sections I've added are (I cannot seem to link directly to them):
|
@abhijit-vmw it's worth mentioning that you can route to each module without a contextPath by assigning a pathPrefix from the WebMvc config to a group of controllers identified with by package or by anything else. It might give you another option to consider. |
I guess it's a strong disagree from me again (still), just so everyone knows. None of the options to make this work are convenient or "natural" for the use case described. Ask someone from the Spring Cloud Gateway team what they expect to happen if you don't believe me. A flag in the filter would be perfect IMO (and it should change the default behaviour also). |
We are facing this issue while using X-Fowarded-* headers to generate resource links.
When we use X-Forwarded-Prefix header in nginx configuration file, it basically replace this path with context path. Instead it should prepend prefix to context path.
For example, if context path is /myapp and if we set prefix to /api, it should return url like https://example.com/api/myapp/ but instead it returns like https://example.com/api/.
We are using spring boot 2.7.3.. I am referring this doc - https://docs.spring.io/spring-hateoas/docs/1.0.4.RELEASE/reference/html/#server.link-builder.forwarded-headers (section 3.4) and using ForwardedHeaderFilter to enable X forwarded headers.
Is there any way to prepend prefix to context path instead of replace?
Steps to reproduce.
curl -v localhost:8080/employees
-H ‘X-Forwarded-Proto: https’
-H ‘X-Forwarded-Host: 'example.com’
-H ‘X-Forwarded-Prefix: /api’
Expected result - href Link should be: https://example.com/api/myapp/hello
Actual result - href Link: https://example.com/api/hello
The text was updated successfully, but these errors were encountered: