Solve the different ContextPath problems in Nginx + Tomcat, nginxcontextpath
1. Problem Description
The project front-end template uses Thymeleaf. When formatting and outputting various URLs, @ {uri} code is used. It automatically reads the virtual path deployed in the project and adds it to the frontend output of the URI.
In actual testing and production environments, we use the deployment mode of nginx + Tomcat, which imposes a constraint: When ngxin configures the proxy, the same context path must be used with the backend application.
A typical test scenario: deploy multiple applications in the same Tomcat, and configure the proxies for the three applications in the same nginx, but they must all be accessed using an independent domain name, context path cannot be added.
2 Thymeleaf implementation principle
Carefully read the source code of Thymeleaf, which encapsulates the uri and is implemented through the LinkBuilder class. Relevant code in the SpringBoot project.
Pay attention to the following points:
1. In the end, request. getContextPath () is called in StandardLinkBuilder to obtain the deployment context.
2. The new StandardLinkBuilder object is directly included in the SpringTemplateEngine constructor.
3. No configuration parameters for LinkBuilder are found in the Code and corresponding configuration definitions of ThymeleafAutoConfiguration.
3 solutions
There are several solutions available based on the project situation.
3.1 Filter + HttpServletRequestWrapper
Idea: The final Code uses request. getContextPath (). We only need to re-encapsulate the Request and rewrite the getContextPath () method.
Add a Filer to the project. The core code is:
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 Extension
We will introduce this method in detail and take this opportunity to familiarize ourselves with the SpringBoot mechanism.
Idea: SpringBoot's default AutoConfiguration does not provide LinkBuilder configuration. We implement an AutoConfiguration by ourselves. After Spring completes SpringTemplateEngine successfully, we will replace the LinkBuilder implementation.
3.2.1 ManualContextLinkBuilder
In this example, the context path is written to/demo. In actual code, it can be implemented through the variables in application. propertis and the maven profile to implement differentiated implementations in different runtime environments.
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 |