如何将子域转换为嵌入式Tomcat 8和Spring引导的路径 [英] How to convert a subdomain to a path with Embedded Tomcat 8 and Spring boot

查看:116
本文介绍了如何将子域转换为嵌入式Tomcat 8和Spring引导的路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何将子域重写为路径?

How to rewrite subdomains to paths?

示例:


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

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

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

Or better would be (reverse folders):


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

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

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

Requesting foo.bar .example.com should ship a file in /src/main/resources/static/ bar/foo /index.html.

使用Apache2它由 mod_rewrite 完成。
我找到了有关用 Tomcat 8 重写的文档,但问题是是使用春季启动放置此文件的位置?

With Apache2 it is done by mod_rewrite. I found documentation about rewriting with Tomcat 8 but the question is where to put this files using spring boot?

更新

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

I tried using the UrlRewriteFilter, but it seems not possible to define rules in the domain path using regexes substitution.

这是我的配置:

Maven依赖关系:

Maven Dependency:

<dependency>
    <groupId>org.tuckey</groupId>
    <artifactId>urlrewritefilter</artifactId>
    <version>4.0.3</version>
</dependency>

Spring Java Config注册Servlet过滤器:

Spring Java Config to register the Servlet Filter:

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

urlrewrite.xml in / src / main / webapp / WEB-INF

urlrewrite.xml in /src/main/webapp/WEB-INF

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE urlrewrite
    PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
    "http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">

<urlrewrite>
    <rule>
        <name>Translate</name>
        <condition name="host" operator="equal">foo.bar.example.com</condition>
        <from>^(.*)</from>
        <to type="redirect">example.com/bar/foo</to>
    </rule>
</urlrewrite>

这个硬编码域可以运行,但它应该适用于每个子域都是这样的。

With this hardcoded domain it works, but it should work for every subdomain like this.

推荐答案

创建自己的过滤器。

此过滤器应该:


  • 检查您是否必须重写您的请求

  • 如果是,重写URL和URI

  • 转发请求

  • 它再次通过相同的过滤器,但首先检查将提供错误

  • 不要忘记并小心打电话给 chain.doFilter

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

你需要一个可以捕捉所有东西的控制器

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

我不确定是否这是必要的,以覆盖 HttpServletRequestWrapper 中的其他方法。这是评论的原因。

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, ...).

这篇关于如何将子域转换为嵌入式Tomcat 8和Spring引导的路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆