如何将子域转换为嵌入式Tomcat 8和Spring引导的路径 [英] How to convert a subdomain to a path with Embedded Tomcat 8 and Spring boot
问题描述
如何将子域重写为路径?
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屋!