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

Issues resolving image @{} while using both context path and spring cloud gateway as reverse proxy #267

Closed
antechrestos opened this issue Nov 25, 2021 · 2 comments

Comments

@antechrestos
Copy link

Runtime context

  • springboot version 2.5.5
  • spring cloud 2020.0.4
  • Thymeleaf 2.0.12

Context

I have two application: the first one is a spring cloud gateway running (let's say locally to make it easier it) with a simple discovery

server:
  port: 8080

spring:
  cloud:
     gateway:
       discovery:
         locator:
           url-expression: "uri"
           predicates:
             - name: Path
               args:
                 patterns:
                   - "'/' + serviceId + '/**'" 
           filters:
             - name: RewritePath
               args:
                 regexp: "'/' + serviceId + '/?(?<remaining>.*)'" 
                 replacement: "'/${remaining}'"
    discovery:
      client:
        simple:
          instances:
            gui:
               - uri: http://localhost:${aas.local.ports.admin}
                  metadata:
                    management.context-path: /manage

And the proxified spring boot named gui with following configuration

server:
  port: 8081
  forward-headers-strategy: "FRAMEWORK"

With this configuration (without context path for gui application), any use of @{/js/resource.js} for example, will work like charm when gui application is accessed through spring gateway application.

For instance, provided that /home endpoint of gui application serve a template that has th:src=@{/js/my-js.js}, when accessing

http://localhost:8080/gui/home, the computed url of js in served page will be http://localhost:8080/gui/js/my-js.js.

Also, while working directly on gui application, I can access to my endpoint through http://localhost:8081/home and it will resolve js address to http://localhost:8081/js/my-js.js

So far so good.

However, when I put a context path on my gui application, things are a little bit different.

I set then server.servlet.context-path: /my/context/path on gui application and while navigating to http://localhost:8081/gui/my/context/path/home, it serves me the computed template with computed url pointing to http://localhost:8080/gui/js/my-js.js instead of http://localhost:8080/gui/my/context/path/js/my-js.js .

Accessing gui directly (http://localhost:8081/my/context/path/home) does resolve js with context path to http://localhost:8081/my/context/path/js/my-js.js

Anything that I am missing?

Thank you

@antechrestos
Copy link
Author

After investigation, seems like spring filter is eating the context path ... Enjoy your meal 😄

@antechrestos
Copy link
Author

antechrestos commented Nov 26, 2021

For anyone encountering this behaviour

public class ForceContextPathFilter extends OncePerRequestFilter {

  
    public ForceContextPathFilter(String contextPath) {
      
        this.contextPath = contextPath;
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        return false; // filter path you don't want to impact
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        if (contextPathIsSet() && !contextPath.equals(request.getContextPath())) {
            UriComponents uriComponents = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request)).build();
           final String scheme = uriComponents.getScheme();
           final String host = uriComponents.getHost();
           final String port = uriComponents.getPort();
           final String path = new UrlPathHelper().getPathWithinApplication(request);
            HttpServletRequestWrapper wrappedRequest = new HttpServletRequestWrapper(request) {

                 @Override
                 public String getContextPath() {
                   return super.getContextPath() + ForceContextPathFilter.this.contextPath;
                 }
                 
                @Override
                public String getRequestURI() {
                    return this.getContextPath()+path;
                }
                
                @Override
                public StringBuffer getRequestURL() {
                    return new StringBuffer()
                          .append(scheme)
                          .append("://")
                          .append(host)
                          .append(":")
                          .append(port)
                          .append(this.getContextPath())
                          .append(path);
                }
            };
            chain.doFilter(wrappedRequest, response);
        } else {
            chain.doFilter(request, response);
        }
    }

    private boolean contextPathIsSet() {
        return !"".equals(contextPath) && !"/".equals(contextPath);
    }
}

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

No branches or pull requests

1 participant