Spring 弹簧&x27;s flashAttributes don';不能在反向代理后工作

Spring 弹簧&x27;s flashAttributes don';不能在反向代理后工作,spring,tomcat,spring-mvc,redirect,proxy,Spring,Tomcat,Spring Mvc,Redirect,Proxy,我在尝试使重定向属性的flashAttributes工作时遇到问题。 我已经在Tomcat7.0上安装了一个用SpringMVC构建的网站,并使用ApacheModu代理和ajp创建了一个反向代理 中也描述了我面临的问题,但这里提供的答案并不适用于我的情况(我使用的是Tomcat的一个实例) 这是我用于测试目的的控制器的一个片段: @RequestMapping(value = "/land", method = RequestMethod.GET) public String land

我在尝试使重定向属性的flashAttributes工作时遇到问题。 我已经在Tomcat7.0上安装了一个用SpringMVC构建的网站,并使用ApacheModu代理和ajp创建了一个反向代理

中也描述了我面临的问题,但这里提供的答案并不适用于我的情况(我使用的是Tomcat的一个实例)

这是我用于测试目的的控制器的一个片段:

@RequestMapping(value = "/land", method = RequestMethod.GET)
    public String land(RedirectAttributes redirectAttrs, Model model) {
    return "redirect_landing";
}

@RequestMapping(value = "/redirect", method = RequestMethod.GET)
public String redirect(RedirectAttributes redirectAttrs, HttpSession session) {

    // add a session message
    session.setAttribute("sessionMessage", "a session message");

    // add a flash message
    redirectAttrs.addFlashAttribute("flashMessage", "a flash message");

    // define the base url
    String baseUrl = "http://localhost:8080/MyApp/";
    // String baseUrl = "http://dev.myapp.lan/";

    return "redirect:" + baseUrl + "land";
}
模板就这么简单:

Flash message: ${flashMessage}
Session message: ${sessionMessage}
相同的代码给出不同的结果,这取决于我是直接通过Tomcat还是通过apache反向代理访问网站:

Tomcat的回应:
闪光信息:闪光信息
会话消息:会话消息

apache mod_代理背后的
Flash消息:
会话消息:会话消息

为什么通过代理访问网站时没有flash消息

我检查了和的代码,但是没有足够的信息(显然逻辑是在别处实现的)

注意:我总是可以回到会话属性来实现我的目标,但是对于那些在反向代理后面使用Tomcat的人来说,这个问题已经足够有趣了


代理配置(代码段):


ServerName dev.myapp.lan
ProxyPass/ajp://localhost:8009/MyApp/
ProxyPassReverseCookiePath/MyApp/
ProxyPassReverseCokieDomain本地主机MyApp
ErrorLog/var/log/apache2/phonebook-error.log
日志级别警告
CustomLog/var/log/apache2/phonebook-access.log组合

TIA。

更改反向代理中的上下文路径通常会导致问题。假设这是一个问题,你有两个选择

  • 通过将MyApp.war重命名为ROOT.war(如果是目录,则将MyApp目录重命名为ROOT),将应用程序部署为Tomcat上的根应用程序

  • 启动一个合适的工具来查看HTTP头和内容(Wireshark、FireBug、ieHttpHeaders等-选择一个适合您和您的环境的工具),并找到所有需要更改和未更改路径的地方。使用mod_头和mod_替换(或等效项)在反向代理中进行必要的更改

  • 就我个人而言,我总是选择1,因为它更简单、更快、更容易,而且更不容易出错。当客户坚持必须更改反向代理中的上下文路径时,我花了几天时间帮助他们调试问题

    为什么会发生这种情况

    当反向代理中的上下文路径更改时,可能需要在许多地方更改该路径:

  • 从用户代理接收的请求URL
  • 后端服务器返回的重定向位置
  • 网页中链接的URL
  • 应用程序(或应用程序正在使用的库)设置的自定义HTTP响应头
  • Cookie路径
  • ProxyPass句柄1

    ProxyPassReverse处理位置、内容位置和URI头(2)

    ProxyPassReverseCookiePath句柄5

    mod_代理不处理案例4或案例5,因为这很难正确处理。最终,您必须逐个编写一些非常仔细的正则表达式,以获得所需的结果


    我怀疑flashAttributes使用的是包含路径的自定义HTTP头,这就是它们无法工作的原因。会话将按照会话cookie通常管理的方式工作,并且您已经配置了ProxyPassReverseCookiePath。

    我知道这个问题已经很老了

    但是有一种方法可以通过代理和Spring Flash属性来解决这个问题

    我为FlashMapManager创建了一个定制的实现,覆盖了isFlashMapForRequest方法

    public class CustomSessionFlashMapManager extends SessionFlashMapManager {
    
        @Override
        protected boolean isFlashMapForRequest(FlashMap flashMap, HttpServletRequest request) {
            String prefixApplicationName = "myApp/";
    
            String expectedPath = flashMap.getTargetRequestPath();
            if (expectedPath.startsWith(prefixApplicationName)) {
                expectedPath = expectedPath.replace(prefixApplicationName, "");
            }
            if (expectedPath != null) {
                String requestUri = getUrlPathHelper().getOriginatingRequestUri(request);
                requestUri = requestUri.replace(prefixApplicationName, "");
                if (!requestUri.equals(expectedPath) && !requestUri.equals(expectedPath + "/")) {
                    return false;
                }
            }
            MultiValueMap<String, String> actualParams = getOriginatingRequestParams(request);
            MultiValueMap<String, String> expectedParams = flashMap.getTargetRequestParams();
            for (String expectedName : expectedParams.keySet()) {
                List<String> actualValues = actualParams.get(expectedName);
                if (actualValues == null) {
                    return false;
                }
                for (String expectedValue : expectedParams.get(expectedName)) {
                    if (!actualValues.contains(expectedValue)) {
                        return false;
                    }
                }
            }
            return true;
        }
    
        private MultiValueMap<String, String> getOriginatingRequestParams(HttpServletRequest request) {
            String query = getUrlPathHelper().getOriginatingQueryString(request);
            return ServletUriComponentsBuilder.fromPath("/").query(query).build().getQueryParams();
        }
    }
    
    公共类CustomSessionFlashMapManager扩展SessionFlashMapManager{
    @凌驾
    受保护的布尔值isFlashMapForRequest(FlashMap FlashMap、HttpServletRequest请求){
    字符串前缀applicationname=“myApp/”;
    字符串expectedPath=flashMap.getTargetRequestPath();
    if(expectedPath.startsWith(前缀applicationname)){
    expectedPath=expectedPath.replace(前缀applicationName,“”);
    }
    if(expectedPath!=null){
    字符串requestUri=getUrlPathHelper().getOriginatingRequestUri(请求);
    requestUri=requestUri.replace(前缀applicationname,“”);
    如果(!requestUri.equals(expectedPath)和&!requestUri.equals(expectedPath+“/”){
    返回false;
    }
    }
    多值映射actualParams=getOriginatingRequestParams(请求);
    多值映射expectedParams=flashMap.getTargetRequestParams();
    for(字符串expectedName:expectedParams.keySet()){
    列出actualValues=actualParams.get(expectedName);
    if(实际值==null){
    返回false;
    }
    for(字符串expectedValue:expectedParams.get(expectedName)){
    如果(!ActualValue.contains(expectedValue)){
    返回false;
    }
    }
    }
    返回true;
    }
    私有多值映射getOriginatingRequestParams(HttpServletRequest请求){
    字符串查询=getUrlPathHelper().getOriginatingQueryString(请求);
    返回ServletUriComponentsBuilder.fromPath(“/”).query(query.build().getQueryParams();
    }
    }
    
    并声明一个bean:

    <bean id="flashMapManager" class="my.package.CustomSessionFlashMapManager" >
        </bean>
    
    
    

    与dimi sad一样,Spring使用请求路径来存储和检索flash属性。所以,重定向时的/someUrl在代理之后变成了/myApp/someUrl。

    如何配置反向代理。至少,我们需要查看ProxyPass指令,理想情况下还需要查看所有代理配置。@MarkThomas我用我正在使用的apache配置中的一个片段更新了我的问题。请让我知道这是否足够。非常感谢。确实是换了衣服
    <bean id="flashMapManager" class="my.package.CustomSessionFlashMapManager" >
        </bean>