会话属性在调用客户端重定向后丢失

Session attribute is lost after invoking a client-side redirect

本文关键字:重定向 客户端 属性 调用 会话      更新时间:2023-09-26

以前,servlet使用response.sendRedirect("pages/my_page.jsp?foo=bar");没有问题。会话属性可以在重定向到的后续页面中检索。

目前,我正在改变发送请求的方式。最初,Javascript使用myForm.submit();,但我现在把它改为jQuery.ajax("my_page.jsp?foo=bar", {...});。然后,servlet在JSON响应中包含一个URL而不是response.sendRedirect(),在success函数中,我使用window.location.replace(url);导航到新页面。但是,保存的会话属性不能在后续页面中获取。

我通过在JSP页面中插入<%= session.getId() %>来比较会话id。它们是一样的。这里的问题是session.getAttribute("myAttribute_1")返回重定向到的页面中的null

我不确定这是否重要,但实际上我正在使用超过1个JSP页面执行此任务:

A.jsp --- (redirect) ---> B.jsp --- (redirect) ---> C.jsp

在这种情况下,我如何获得C.jsp中保存的会话属性?


编辑

下面是我用来保存session属性的代码片段。

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    HttpSession session = request.getSession(true);
    response.setContentType("application/json");
    CustomObject customObject = new CustomObject();
    // ...
    session.setAttribute("myAttribute_1", customObject);
    PrintWriter writer = response.getWriter();
    JsonObject json = new JsonObject();
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    json.addProperty("url", "next_page.jsp?foo=bar");
    writer.println(gson.toJson(json));
    writer.close();
}

下面是重定向的代码片段。

function redirectHandler(data, currentUrl) {
    if (data && data.hasOwnProperty('url')) {
        var redirectUrl = data.url;
        jQuery.get(redirectUrl).done(function(response) {
            redirectHandler(response, redirectUrl);
        });
    } else {
        window.location.replace(currentUrl);
    }
}
function sendFormData(method, url, form) {
    jQuery.ajax(url, {
        'method': method,
        'data': parseData(jQuery(form).serializeArray()),
        'success': function(data) {
            redirectHandler(data, window.location.href);
        }
    });
}

结果

我已经恢复使用response.sendRedirect("pages/my_page.jsp?foo=bar")在我的servlet。

客户端删除jQuery.ajax(),更新sendFormData()函数如下:

function sendFormData(form) {
    var data = parseData(jQuery(form).serializeArray());
    var f = document.createElement('form');
    for (var key in data) {
        jQuery('<input>').attr({
            'type': 'hidden',
            'name': key,
            'value': data[key]
        }).appendTo(f);
    }
    f.setAttribute('method', form.getAttribute('method'));
    f.setAttribute('action', form.getAttribute('action'));
    f.submit();
}

每当我想提交一个表单,一个click事件处理程序是附加的。它将调用sendFormData(myOriginalForm);而不是myOriginalForm.submit();,因为我需要自定义要发送的数据。

只有应用这些简单的改变,一切才会恢复正常。

我仍然在寻找一个奇怪行为的解释。

您尝试过不同形式的Javascript重定向吗?

建议的方法是:

window.location.href=currentUrl;

根据本文,使用window.location.replace将取代当前会话

服务器端

HTTP请求是无状态的,会话通过不同的方式放在HTTP之上,如

  • URL重写(例如服务器启动新会话并返回其ID给客户端,然后客户端将会话ID附加到所有后续请求http://host:port/path;session_id=12345)
  • cookie (例如,在会话创建时,服务器响应一个编码会话ID的cookie,而在服务器端,您期望cookie将每个请求与现有会话相关联)。

客户端有责任确保他们以服务器期望的方式参与会话。当使用Java Servlet API实现服务器时,它要么是jsessionid cookie,要么是与URL附加相同名称的查询参数,该URL标识会话id。

如果客户端不支持cookie,使用Java Servlet API您将不得不重定向到HttpServletResponse.encodeRedirectURL(String url)创建的URL。

为了从servlet重定向使用HttpServletResponse.sendRedirect(String url); .

用标准的HTTP重定向响应服务器将简化您的设计。Jquery确实实现了这些标准,因此将尊重来自服务器的HTTP 301302响应,如图所示,因此客户端不需要重定向逻辑。


客户端

您的客户端是jquery,它的ajax实现将尊重并重放为任何给定域设置的cookie,当后续请求将向同一域发出时。

如果你是重定向到一个不同的域,为jquery工作与CORS会话,请添加xhrFields到您的请求:

$.ajax({
    url: a_cross_domain_url,
    xhrFields: {
      withCredentials: true
    }
});

根据这个答案

我也遇到过同样的问题,为了寻找最好的解决方案,我绞尽脑汁。尝试将sessionCookiePath="/"属性放入context.xml根节点:

<Context ... sessionCookiePath="/" > ... </Context>

这将把会话cookie的路径设置为应用程序的根目录,这样它就会被重定向传递。这个简单的修复对我有效。

很多人会建议URL编码或存储会话ID在另一个cookie,但根据我的理解,这是最好的解决方案,如果它适合你。(会话cookie被认为是绝对必要的,因此按预期使用它们可能是最佳实践。)