解决Nginx+Tomcat时ContextPath不同的问题
1 问题描述
项目前端模板使用Thymeleaf,在对各种URL进行格式化输出时,都使用@{uri}代码。它会自动读取项目部署的虚拟路径,添加到URI的前端输出。
真实测试和生产环境中,我们使用nginx+Tomcat的部署模式,这就会部署带来一个限制:ngxin配置proxy时,需要同后端application使用相同的context path。
一个比较典型的测试场景:同一个Tomcat,部署多个应用;同一个nginx,配置这三个应用的proxy,但要求都使用独立域名进行访问,不能添加 context path。如图:

2 Thymeleaf实现原理
仔细读Thymeleaf的源码,它对uri的封装,是通过 LinkBuilder类实现的。在SpringBoot项目中,相关的代码。

有几点需要注意:
1、 最终是在 StandardLinkBuilder中调用request.getContextPath()获取部署context.
2、 SpringTemplateEngine的构造函数中,直接new StandardLinkBuilder对象。
3、 ThymeleafAutoConfiguration的代码和相应的配置定义中,没有发现对LinkBuilder的配置参数。
3 解决方案
根据项目情况,可以有几个解决方案可供选择。
3.1 Filter + HttpServletRequestWrapper
思路:最终代码使用request.getContextPath(),我们只要重新封装一下Request,重写getContextPath()方法即可。

并在项目中添加一个Filer,核心代码为:
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { CustomContextPathRequest requestWrapper = new CustomContextPathRequest( (HttpServletRequest) request, this.contextPath); filterChain.doFilter(requestWrapper, response); } |
3.2 扩展 AutoConfiguration
咱重点介绍一下这个方法,借此机会熟悉SpringBoot的机制。
思路:SpringBoot缺省的AutoConfiguration没有提供配置LinkBuilder,我们自己实现一个AutoConfiguration,在Spring完成SpringTemplateEngine成功之后,再替换器LinkBuilder实现。

3.2.1 ManualContextLinkBuilder
例子是将context path写死为 /demo ,实际代码中,可以通过在application.propertis中的变量来实现,并配合maven profile,实现不同运行环境的差异化实现。
|
public class ManualContextLinkBuilder extends StandardLinkBuilder { private String nginxContextPath = “/demo”; @Override protected String computeContextPath(final IExpressionContext context, final String base, final Map<String, Object> parameters) { return nginxContextPath; } } |
3.2.2 ManualContextLinkBuilderConfiguration
|
@Configuration @AutoConfigureAfter(WebMvcAutoConfiguration.class) public class ManualContextLinkBuilderConfiguration { @Autowired SpringTemplateEngine springTemplateEngine; @Bean public ILinkBuilder linkBuilder() { ILinkBuilder linkBuilder = new ManualContextLinkBuilder(); springTemplateEngine.setLinkBuilder(linkBuilder); return linkBuilder; } } |
3.2.3 META-INF/spring.factories
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ tech.codestory.ManualContextLinkBuilderConfiguration |
解决Nginx+Tomcat时ContextPath不同的问题的更多相关文章
- 【nginx】解决Nginx重启时提示nginx: [emerg] bind() to 0.0.0.0:80错误
Nginx是一款轻量级的Web服务器,特点是占有内存少,并发能力强,因而使用比较广泛,蜗牛今天在一个VPS上重启Nginx时提示“nginx: [emerg] bind() to 0.0.0.0:80 ...
- 解决Nginx重启时提示nginx: [emerg] bind() to 0.0.0.0:80错误
Nginx是一款轻量级的Web服务器,特点是占有内存少,并发能力强,因而使用比较广泛,蜗牛今天在一个VPS上重启Nginx时提示“nginx: [emerg] bind() to 0.0.0.0:80 ...
- 解决启动Tomcat时遇到INFO: Destroying ProtocolHandler ["ajp-apr-8009"]
问题描述: 启动Tomcat时,出现INFO: Destroying ProtocolHandler ["ajp-apr-8009"]等信息 这说明端口号被占用了... 解决方法: ...
- 解决nginx启动时域名解析失败而导致服务启动失败的问题
问题: nginx启动或者reload的时候,会对proxy_pass后面的域名进行DNS解析,如果解析失败,启动就会失败或者reload失败. 我们是to B的产品,客户的环境可能是不通公网的,因此 ...
- 解决Nginx+Tomcat下客户端https请求跳转成http的问题
Nginx上开启https, 后端使用Tomcat, 两者间走http协议, 但发现如果tomcat应用存在跳转时, 则客户端浏览器会出现400 Bad Request的错误, 通过抓包发现原因是 ...
- 解决Nginx+Tomcat中https转http请求问题---解决js加载使用http的问题
解决js加载使用http的问题 控制台错误提示: Mixed Content: The page at '' was loaded over HTTPS, but requested an insec ...
- Nginx+tomcat负载均衡时静态页面报404
百度到的问题解决BLOG http://os.51cto.com/art/201204/326843.htm nginx+2台tomcat负载均衡,应用程序已部署,单独访问tomcat时,可以访问到所 ...
- 解决eclipse配置Tomcat时找不到server选项(Mac通用)
集成Eclipse和Tomcat时找不到server选项: 按照网上的步骤如下: 在Eclipse中,窗口(window)——首选项(preferences)——服务器(Server)——运行时环境( ...
- [转]Eclipse启动Tomcat时45秒超时解决方法
原文地址:http://it.oyksoft.com/post/6577/ Eclipse启动Tomcat时,默认配置的启动超时时长为45秒.假若项目启动超过45秒将会报错.两种解决方法:1.改XML ...
随机推荐
- 201521123033《Java程序设计》第9周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. answer: 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号 ...
- 201521123059 《Java程序设计》第十周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 多线程的相关理解图: 2. 书面作业 本次PTA作业题集异常.多线程 Q1:finally 题目4-2 1. ...
- 201521123114 《Java程序设计》第11周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 Q1. 互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用syn ...
- 201521123023《Java程序设计》第11周学习总结
1. 本周学习总结 Lock.Condition,互斥同步访问方法,相比于synchronized,相似的wait().notify().notifyAll()方法,还有更多高级的方法 Executo ...
- Eclipse rap 富客户端开发总结(11) : rcp/rap与spring ibatis集成
1. rcp/rap 与 spring 集成 Activator 是rcp/rap 启动时需要加载的类, 只需要加载一遍,所以与spring 集成的时候一般是在这个类里面加载spring 的Appli ...
- 框架应用:Mybatis (一) - 入门案例
ORM框架 在实际开发中,工程中本质的任务是从数据库中获取数据,然后对数据进行操作,又或者写入数据.开发时语言是大多是面向对象的工程语言,这个时候就必须进行工程语言和数据库连接语言的转换,也就是所谓的 ...
- CSS1-3基礎知識
CSS1-3基礎知識 1.css排版 css在html內排版: <style type='text/css'> 標記名{} .類型名{} #ID名{} 標記名,.類型名,#ID名{} &l ...
- python进阶之Socket 网络编程
一:网络编程介绍 自从互联网诞生以来,现在基本上所有的程序都是网络程序,很少有单机版的程序了. 计算机网络就是把各个计算机连接到一起,让网络中的计算机可以互相通信.网络编程就是如何在程序中实现两 ...
- appium 原理解析
Appium是 c/s模式的appium是基于 webdriver 协议添加对移动设备自化api扩展而成的webdriver 是基于 http协议的,第一连接会建立个 session 会话,并通过 p ...
- ThinkJS框架入门详细教程(一)开发环境
一.前端标配环境 1.nodeJS正确安装,可以参考:http://www.cnblogs.com/chengxs/p/6221393.html 2.git正确安装,可以参考:http://www.c ...