How to convert a subdomain to a path with Embedded Tomcat 8 and Spring boot

前端 未结 4 1418
执念已碎
执念已碎 2021-02-06 04:57

How to rewrite subdomains to paths?

Example:

  • foo.bar .example.com --> example.com /foo/bar

Or better woul

4条回答
  •  不思量自难忘°
    2021-02-06 05:26

    Create you own Filter.

    This Filter should:

    • check if you have to rewrite your request
    • If yes, rewrite URL and URI
    • forward request
    • it comes again through same filter, but first check will deliver false
    • don't forget and be carefull to call chain.doFilter

    Forwarding will not change any URLs in browser. Just ship content of file.

    Follow code could be implementation of such filter. This is not any kind of clean code. Just quick and dirty working code:

    @Component
    public class SubdomainToReversePathFilter implements Filter {
        @Override
        public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
            final HttpServletRequest req = (HttpServletRequest) request;
            final String requestURI = req.getRequestURI();
    
            if (!requestURI.endsWith("/")) {
                chain.doFilter(request, response);
            } else {
                final String servername = req.getServerName();
                final Domain domain = getDomain(servername);
    
                if (domain.hasSubdomain()) {
                    final HttpServletRequestWrapper wrapped = wrapServerName(req, domain);
                    wrapped.getRequestDispatcher(requestURI + domain.getSubdomainAsPath()).forward(wrapped, response);
                } else {
                    chain.doFilter(request, response);
                }
            }
        }
    
        private Domain getDomain(final String domain) {
            final String[] domainParts = domain.split("\\.");
            String mainDomain;
            String subDomain = null;
    
            final int dpLength = domainParts.length;
            if (dpLength > 2) {
                mainDomain = domainParts[dpLength - 2] + "." + domainParts[dpLength - 1];
    
                subDomain = reverseDomain(domainParts);
            } else {
                mainDomain = domain;
            }
    
            return new Domain(mainDomain, subDomain);
        }
        private HttpServletRequestWrapper wrapServerName(final HttpServletRequest req, final Domain domain) {
            return new HttpServletRequestWrapper(req) {
                @Override
                public String getServerName() {
                    return domain.getMaindomain();
                }
                // more changes? getRequesetURL()? ...?
            };
        }
    
        private String reverseDomain(final String[] domainParts) {
            final List subdomainList = Arrays.stream(domainParts, 0, domainParts.length - 2)//
                    .collect(Collectors.toList());
    
            Collections.reverse(subdomainList);
    
            return subdomainList.stream().collect(Collectors.joining("."));
        }
    
        @Override
        public void init(final FilterConfig filterConfig) throws ServletException {
        }
    
        @Override
        public void destroy() {
        }
    }
    

    Here is Domain class:

    public static class Domain {
        private final String maindomain;
        private final String subdomain;
    
        public Domain(final String maindomain, final String subdomain) {
            this.maindomain = maindomain;
            this.subdomain = subdomain;
        }
    
        public String getMaindomain() {
            return maindomain;
        }
    
        public String getSubdomain() {
            return subdomain;
        }
    
        public boolean hasSubdomain() {
            return subdomain != null;
        }
    
        public String getSubdomainAsPath() {
            return "/" + subdomain.replaceAll("\\.", "/") + "/";
        }
    }
    

    And you need a Controller that catches everything

    @RestController
    public class CatchAllController {
    
        @RequestMapping("**")
        public FileSystemResource deliver(final HttpServletRequest request) {
            final String file = ((String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE));
    
            return new FileSystemResource(getStaticFile(file));
        }
    
        private File getStaticFile(final String path) {
            try {
                // TODO handle correct
                return new File(CatchAllController.class.getResource("/static/" + path + "/index.html").toURI());
            } catch (final Exception e) {
                throw new RuntimeException("not found");
            }
        }
    }
    

    I'm not sure if this is necessary to override other methods in HttpServletRequestWrapper. That's reason for comment.

    Also you have to handle cases for file delivery (not existent, ...).

提交回复
热议问题