Servlet的sendRedirect()方法导致我的会话属性丢失

10

我在WinXP、Eclipse Indigo和Google Web插件上开发一个Web应用程序。

我有一个简单的表单,让用户输入一个值(例如电子邮件),将其传递给名为SignIn.java的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,并且它们没问题(肯定是相同的会话,因为这是我的Web应用程序创建的第一个且唯一的会话,而且我甚至还特意检查了会话ID,两个请求的ID是相同的)。

sendRedirect()forward()之间为什么会有区别?简单的解决方案是使用forward(),但在放手之前我想要弄清楚这个问题,我认为理解发生了什么很重要。对于这些基本概念,我不确定自己不知道发生了什么(因为我是初学者,所以我的整个Web应用程序非常简单和基础)。

任何想法或建议都将受到热烈欢迎!


我猜现在可能可以使用forward而不是sendredirect,但我认为以后我想使用sendredirect而不必担心我的会话属性会无缘无故地变成null。 - Joel Blum
@home:OP确认会话ID在之前和之后是相同的。 - BalusC
1
当您不发送重定向并手动从浏览器访问/ShowOnlineServlet时会发生什么? - Oleg Mikheev
好的,我认为问题可能是我创建了一个不可序列化的对象并将其存储在会话中。 - Joel Blum
1
非常重要的是确保你的属性实现了Serializable接口,否则你会遇到愚蠢的错误(令人沮丧的是,在本地一切运行正常,但一旦部署到服务器上,你可能会发现属性为null)。 - Joel Blum
2个回答

1

如果您的SignIn servlet只保存了一个请求参数(email),那么您也可以用过滤器filter替换该servlet,例如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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接