【问题标题】:Servlet's sendRedirect() kills my session attributesServlet 的 sendRedirect() 杀死了我的会话属性
【发布时间】:2011-12-23 05:05:50
【问题描述】:

我正在开发一个使用 WinXP、Eclipse Indigo 和 Google 网络插件的网络应用程序。

我有一个简单的表单,它从用户(例如电子邮件)获取一个值,将它传递给一个名为 SignIn.java 的 servlet,该 servlet 处理它并将电子邮件值保存到会话中。 SignIn 的代码非常简单,下面是它的doGet 的主要作用:

String email = req.getParameter("email");   //getting the parameter from html form
...
...
HttpSession session = req.getSession();     //create a new session
session.setAttribute("email", email);

到目前为止一切顺利,我已验证此时的值不是null。现在问题来了,我想重定向到另一个需要进行更多处理的 servlet (ShowOnline.java)。当我写作时

resp.sendRedirect(resp.encodeRedirectURL("/ShowOnlineServlet")); 

ShowOnline 获取 null 会话值(我之前保存的相同电子邮件属性现在是 null

当我写作时

getServletConfig().getServletContext().getRequestDispatcher("/ShowOnlineServlet");

一切正常,之前的email属性不是null

发生了什么事? sendRedirect() 只是让您的浏览器发送一个新请求,它不应该影响会话范围。我已经检查了 cookie,它们很好(肯定是之前的同一个会话,因为它是我的 webapp 创建的第一个也是唯一一个会话,而且我什至费心检查了 sesison ID,它们在两个请求上都是相同的) .

为什么sendRedirect()forward() 之间会有区别?简单的解决方案是使用forward(),但我想在我放手之前深入了解这一点,我认为了解发生的事情对我来说很重要。我不确定我是否喜欢不知道这些基本概念发生了什么的想法(我的整个 web 应用程序在这一点上非常简单和基本,因为我是初学者)。

热烈欢迎任何想法或建议!

【问题讨论】:

  • 我想目前可以使用 forward 而不是 sendredirect 但我想稍后我想使用 sendredirect 而不必担心我的会话属性会无缘无故地变为空。跨度>
  • @home:OP确认会话ID前后一致。
  • 当您不发送重定向并从浏览器手动转到 /ShowOnlineServlet 时会发生什么?
  • 好的,我认为问题可能是我创建了一个不可序列化的对象并将其存储在会话中。
  • 确保你的属性实现 Serializable 接口非常重要,否则你会得到愚蠢的错误(令人沮丧的是,本地一切正常,但一旦你部署到你的服务器,你可能会发现空属性) .

标签: java session servlets attributes


【解决方案1】:

如果您的 SignIn servlet 仅保存请求参数(电子邮件),那么您也可以将 servlet 替换为 filter,例如SignInFilter.

SignInFilter 将包含与您的 SignIn servlet 相同的逻辑(将电子邮件从请求参数复制到会话),但会调用链中的下一个项目(这将是您的 ShowOnline servlet)做任何重定向/转发。

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
    throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    HttpSession session = request.getSession();

    String email = req.getParameter("email");
    session.setAttribute("email", email);

    chain.doFilter(req, res); // continue to 'ShowOnline'

}

将您的表单设置为 POST 到 ShowOnline servlet,并将您的新 SignInFilter 配置为在 ShowOnline 之前执行(为简洁起见,下面省略了 servlet 映射)。

<?xml version="1.0" encoding="UTF-8"?>
<web-app 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">

    <filter>
        <filter-name>SignInFilter</filter-name>
        <filter-class>com.example.SignInFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>SignInFilter</filter-name>
        <url-pattern>/ShowOnline</url-pattern>
    </filter-mapping>
</web-app>

【讨论】:

    【解决方案2】:

    据我所知,sendRedirect() 只是将控件重定向到另一个页面,而不传输父页面的关联请求和响应对象,但 RequestDispatcher(object) 会将 ServletRequest 和 ServletResponse 分派到路径参数中提到的页面 { getServletContext().getRequestDispatcher("path")} 之后,您可以将对象转发到该页面或包含对象。因此,通过这个容器可以确保他必须使用父页面的先前请求和响应对象,而不是创建新的。 特别是如果您使用会话管理,最好的选择是 RequestDispatcher。

    希望能回答这个问题。

    致所有人:- 如果我错了,请纠正我。

    @rs

    【讨论】:

      猜你喜欢
      • 2012-12-31
      • 1970-01-01
      • 2017-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-29
      • 2011-08-11
      相关资源
      最近更新 更多