0

我在尝试使 RedirectAttributes 的 flashAttributes 工作时遇到问题。我已经在 Tomcat 7.0 上设置了一个使用 Spring MVC 构建的网站,并使用 Apache mod_proxy 和 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 的响应:
Flash message: 一条消息
Session message: 一个会话消息

在 apache mod_proxy 后面
Flash 消息:
Session message: 一个会话消息

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

我检查了RedirectAttributesModelMap.javaModelMap.java的代码,但那里没有足够的信息(显然逻辑是在其他地方实现的)。

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


代理配置(片段):

<VirtualHost *:80>
    ServerName dev.myapp.lan    

    ProxyPass / ajp://localhost:8009/MyApp/

    ProxyPassReverseCookiePath /MyApp /
    ProxyPassReverseCookieDomain localhost MyApp

    ErrorLog /var/log/apache2/phonebook-error.log
    LogLevel warn

    CustomLog /var/log/apache2/phonebook-access.log combined
</VirtualHost> 

TIA。

4

2 回答 2

2

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

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

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

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

为什么会这样?

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

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

ProxyPass 处理 1

ProxyPassReverse 处理 Location、Content-Location 和 URI 标头 (2)

ProxyPassReverseCookiePath 句柄 5

mod_proxy 不处理案例 4 或案例 5,因为这很难正确处理。您最终不得不根据具体情况编写一些非常仔细的正则表达式才能获得所需的结果。

我怀疑 flashAttributes 正在使用包含路径的自定义 HTTP 标头,这就是它们不起作用的原因。会话将正常工作,通常由会话 cookie 管理,并且您已配置 ProxyPassReverseCookiePath。

于 2013-10-14T21:00:31.873 回答
0

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

但是有一种方法可以使用代理和 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();
    }
}

并声明一个bean:

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

作为dimi 悲伤,Spring 使用请求路径来存储和检索闪存属性。因此, /someUrl 在重定向时刻,在代理之后变为 /myApp/someURL。

于 2019-11-13T02:37:51.093 回答