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

Posted

技术标签:

【中文标题】调用客户端重定向后会话属性丢失【英文标题】:Session attribute is lost after invoking a client-side redirect 【发布时间】:2016-01-09 15:03:03 【问题描述】:

以前,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中保存的会话属性?


编辑

下面是我用来保存会话属性的代码sn-p。

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();

下面是重定向的代码sn-p。

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);
        
    );


结果

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

在客户端,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();,因为我需要自定义要发送的数据。

只有应用这些简单的更改,一切才能再次运行。

不过,我仍在寻找有关这种奇怪行为的解释。

【问题讨论】:

您能否将您实际保存属性的代码发布到会话中,属性名为 - “myAttribute_1”? @Mr.VishalJGajera 你来了。 如果可能的话,然后将整个代码从哪里发布到你打电话的地方?我认为您犯了一些小错误,但不确定是否需要代码。 @Mr.VishalJGajera 代码已更新。 好的,代码看起来不错。还有另一个疑问,你能告诉我从哪里到哪里进入 1 线。比如,a.jsp ---> Servlet.java ---> newjsp.jsp,也可以根据你的想法检查流程是否完美,还可以根据你的意愿调试代码以检查流程。 【参考方案1】:

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

推荐的方法是:

window.location.href=currentUrl;

根据这个article,使用window.location.replace将替换当前会话。

【讨论】:

能否不重定向并传递参考信息,以便在重定向到新地址后创建新会话? @StevenScott 我可以看到 JSESSIONID 是用 ajax 发送的,原始会话中只有几个属性丢失了。在我的情况下,创建新会话不是一个可行的解决方案。【参考方案2】:

在服务器端

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

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

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

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

要从 servlet 重定向,请使用 HttpServletResponse.sendRedirect(String url);

使用 HTTP 重定向标准从服务器响应将简化您的设计。 Jquery 确实实现了这些标准,因此会将来自服务器的 HTTP 301302 响应视为ilustrated here,因此客户端没有重定向逻辑应该是需要的。


在客户端

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

如果您要重定向到其他域,以便 jquery 使用 CORS 会话,请在您的请求中添加 xhrFields

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

根据this answer

【讨论】:

如果我的 ajax 调用的 URL 中省略了域,是否算作跨域请求?【参考方案3】:

我遇到了同样的问题,tore my hair out looking for the best solution。尝试将sessionCookiePath="/" 属性放入您的 context.xml 根节点:

&lt;Context ... sessionCookiePath="/" &gt; ... &lt;/Context&gt;

这会将会话 cookie 的路径设置为应用的根目录,以便在重定向时传递它。这个简单的修复对我有用。

许多人会建议 URL 编码或将会话 ID 存储在另一个 cookie 中,但根据我的理解,如果它适合您,这是最好的解决方案。 (会话 cookie 为 considered strictly necessary,因此按预期使用它们可能是最佳做法。)

【讨论】:

以上是关于调用客户端重定向后会话属性丢失的主要内容,如果未能解决你的问题,请参考以下文章

重定向时丢失会话(node.js + socket.io)

在 Codeigniter 中重定向后会话丢失

重定向后 ASP Net Core 2.2 会话丢失

OAuth 重定向后会话丢失

重定向到另一个域然后返回后丢失会话

使用 django python-social-auth 重定向后会话值丢失