解決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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM