如何将子域转换为嵌入式Tomcat 8和Spring引导的路径

如何将子域重写到路径?

例:

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

或者更好(反向文件夹):

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

请求foo.bar .example.com应该在/ src / main / resources / static / bar / foo /index.html中发送文件。

使用Apache2,它由mod_rewrite完成。 我找到了有关使用Tomcat 8重写的文档,但问题是在哪里使用spring boot放置这些文件?


更新

我尝试使用UrlRewriteFilter ,但似乎无法使用正则表达式替换在域路径中定义规则。

这是我的配置:

Maven依赖:

 org.tuckey urlrewritefilter 4.0.3  

Spring Java Config注册Servletfilter:

 @Configuration @ComponentScan @EnableAutoConfiguration public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new UrlRewriteFilter()); registrationBean.addUrlPatterns("*"); registrationBean.addInitParameter("confReloadCheckInterval", "5"); registrationBean.addInitParameter("logLevel", "DEBUG"); return registrationBean; } } 

/ src / main / webapp / WEB-INF中的urlrewrite.xml

     Translate foo.bar.example.com ^(.*) example.com/bar/foo   

使用这个硬编码域它可以工作,但它应该适用于这样的每个子域。

创建自己的filter。

此filter应该:

  • 检查您是否必须重写您的请求
  • 如果是,请重写URL和URI
  • 转发请求
  • 它再次通过相同的filter,但第一次检查将提供错误
  • 不要忘记并小心调用chain.doFilter

转发不会更改浏览器中的任何URL。 只需发送文件内容。

遵循代码可以实现这样的filter。 这不是任何一种干净的代码。 只是快速而肮脏的工作代码:

 @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() { } } 

这是Domain类:

 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("\\.", "/") + "/"; } } 

而且你需要一个可以捕捉一切的控制器

 @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"); } } } 

我不确定是否有必要覆盖HttpServletRequestWrapper其他方法。 这是评论的理由。

此外,您还必须处理文件传递的情况(不存在,……)。

您可以使用Backreferences来使用在中匹配的分组部件。 像这样的东西 –

 (*).(*).example.com ^(.*) example.com/%1/%2 

当然,您必须调整上面的条件规则才能停止热切匹配。

更多信息 – http://urlrewritefilter.googlecode.com/svn/trunk/src/doc/manual/4.0/index.html#condition

解决此问题的另一种方法:在Controller本身中执行此操作。 在我看来,这比使用filter更好,因为:

  • filter捕获每个请求。 在这里,您可以更好地控制应使用“子域模式”传递哪些请求。 例如,我选择了/subdomain2path
  • 您不必更改/包装URI / URL并再次通过filter链转发。
  • 所有逻辑都在此控制器中

方法getSubdomainreverseDomain与之前的回答相同。

这是impl:

 @RestController @RequestMapping("/subdomain2path") public class Subdomain2PathController { @RequestMapping("/") public FileSystemResource deliver(final HttpServletRequest request) { final Domain subdomain = getSubdomain(request.getServerName()); String file = "/"; if (subdomain.hasSubdomain()) { file = subdomain.getSubdomainAsPath(); } return new FileSystemResource(getStaticFile(file)); } private Domain getSubdomain(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 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(".")); } private File getStaticFile(final String path) { try { // TODO handle correct return new File(Subdomain2PathController.class.getResource("/static/" + path + "/index.html").toURI()); } catch (final Exception e) { throw new RuntimeException("not found"); } } } 

域类与之前的答案相同:

 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("\\.", "/") + "/"; } } 

它对我有用。 希望它也适用于其他人。

请使用以下依赖项


   org.tuckey urlrewritefilter 4.0.4  

在资源文件夹中创建了urlrewrite.xml

      Domain Name Check www.userdomain.com ^(.*)$ http://www.userdomain.com$1  


在主ApplicationRunner.java中添加

 @Bean public FilterRegistrationBean tuckeyRegistrationBean() { final FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new CustomURLRewriter()); return registrationBean; } 

并创建了CustomURLRewriter

 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.core.io.ClassPathResource; import org.tuckey.web.filters.urlrewrite.Conf; import org.tuckey.web.filters.urlrewrite.UrlRewriteFilter; import org.tuckey.web.filters.urlrewrite.UrlRewriter; import javax.servlet.*; import java.io.InputStream; public class CustomURLRewriter extends UrlRewriteFilter { private UrlRewriter urlRewriter; @Autowired Environment env; @Override public void loadUrlRewriter(FilterConfig filterConfig) throws ServletException { try { ClassPathResource classPathResource = new ClassPathResource("urlrewrite.xml"); InputStream inputStream = classPathResource.getInputStream(); Conf conf1 = new Conf(filterConfig.getServletContext(), inputStream, "urlrewrite.xml", ""); urlRewriter = new UrlRewriter(conf1); } catch (Exception e) { throw new ServletException(e); } } @Override public UrlRewriter getUrlRewriter(ServletRequest request, ServletResponse response, FilterChain chain) { return urlRewriter; } @Override public void destroyUrlRewriter() { if(urlRewriter != null) urlRewriter.destroy(); } }