【问题标题】:Captcha servlet causes java.lang.IllegalStateException: PWC3999: Cannot create a session after the response has been committedCaptcha servlet 导致 java.lang.IllegalStateException: PWC3999: 提交响应后无法创建会话
【发布时间】:2011-01-04 13:24:28
【问题描述】:

我正在使用 SimpleCaptcha 创建一个验证码输入,并验证了验证码输入。我使用以下代码创建了一个验证码输入。

HTML 代码:

<form action="submit_proceed.do" method="post">
<img src="captchaImg" /><input type="text" name="captcha" value=""><br />
<input type="submit" value="Submit" name="submit" />
</form>

JavaServlet 代码:

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Iterator;
import nl.captcha.Captcha;

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();

List errorMsgs = new LinkedList();
try{
    // Validate Captcha
    HttpSession session = request.getSession(true);
    String userCaptcha = request.getParameter("captcha");
    Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
    if (!captcha.isCorrect(userCaptcha)) {
        errorMsgs.add("Please input the correct Captcha value.");
    }
} catch (RuntimeException e) {
    errorMsgs.add("An unexpected error: " + e.getMessage());
    RequestDispatcher view = request.getRequestDispatcher("/error.view");
    view.forward(request, response);
}

但是我一直收到这个错误:

StandardWrapperValve[Captcha]: PWC1406: Servlet.service() for servlet Captcha threw exception
java.lang.IllegalStateException: PWC3999: Cannot create a session after the response has been committed

如何在我的 servlet 上创建会话?我该如何解决这个问题?

非常感谢。

【问题讨论】:

  • 您从哪里获得会话?您的方法中是否缺少某些重要部分? HttpSession session = request.getSession(); 或类似声明在哪里?如何获取会话对象?
  • @WildWezyr:我想我测试后不小心把这个删掉了,添加到代码中,HttpSession session = request.getSession(true);

标签: session servlets glassfish captcha simplecaptcha


【解决方案1】:

响应提交后无法创建会话

异常信息非常清楚。有非法状态的手段。当响应已经提交时,您不能再设置/更改响应标头。当标头已经发送到客户端时,将提交响应。这是一个不归路

只要直接刷新(输入)输出流,就会提交响应。当您向响应写入超过 2K 的内容(取决于服务器配置),或者手动执行 flush() 或执行 sendRedirect() 调用时,可能会发生这种情况。

每当需要创建会话时,服务器都需要在响应头中设置一个 cookie,以便它可以识别特定的客户端并将其与服务器内存中的 HttpSession 实例相关联。但如果响应已经提交,则这是不可能的,因此会出现此异常。

回到这个问题的根本原因:

servlet Captcha 的 Servlet.service() 抛出异常

是带有servlet-nameCaptcha 的servlet 导致了这个问题。您需要检查/调试整个请求-响应链,以查看所有调用了哪些 servlet/过滤器,以及它们中的哪些可能在Captcha servlet 能够创建会话之前提交了响应。由于您的 topicstart 中缺少此信息,因此我无法为您提供更多帮助。

至少,在目前给出的代码示例中,我看到您不必要地调用了response.getWriter()。我不确定真实世界的代码是什么样子,也许你已经删除了一些行,但很可能你实际上是在写它,这可能是问题的根本原因。如果你写的太多或做了刷新,那么响应将被提交。不要不要写入应该是控制器的 Servlet 内的响应。那里你通常使用 JSP。或者如果是出于调试目的,请使用标准输出 (System.out.println()) 或 Logger

【讨论】:

  • @BalusC:是的,你是对的。这完全是会话的问题。验证码确实造成了问题。设法通过在生成验证码图像之前转移会话 setAttribute 来解决问题。谢谢。
【解决方案2】:

有问题的代码在nl.captcha.servlet.SimpleCaptchaServlet Servlet 中。如果将其更改为StickyCaptcha,问题就会消失,但具体来说,以下是 SimpleCaptcha Servlet 中的违规行。

CaptchaServletUtil.writeImage(resp, captcha.getImage());
req.getSession().setAttribute(NAME, captcha);

实际上代码是写图像文件来响应(通常大于默认的2k)。

所以暂时您可以使用StickyCaptcha 或签出代码并解决问题。

【讨论】:

    【解决方案3】:

    移动这一行:

    HttpSession session = request.getSession(true);
    

    作为 doPost 方法中的第一个语句。

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    
      HttpSession session = request.getSession(true);
    
      response.setContentType("text/html;charset=UTF-8");
    
      //...
    }
    

    这应该会有所帮助。

    【讨论】:

    • @WildWezyr:移到最上面,但异常信息依然存在。
    • @jl:你确定你在测试之前正确地重建和重新部署了你的 webapp ;-) 吗?在测试应该有效但似乎无效的修复程序时,有时会出现这种情况......
    • @WildWezyr:我通过 netbeans 重建、清理和加载。
    • @jl: 有时 netbeans 中的某些东西会卡住,您必须停止并重新启动 servlet 容器(tomcat 或类似的东西)才能正确重新加载更改后的 webapp...
    【解决方案4】:

    看来,您在处理帖子之前已经将标头发送给了客户端。如果创建会话,服务器需要将会话 ID 发送给客户端。这通常通过发送 cookie 来完成。我想您在将任何内容发送回客户端之前检查您的代码是否执行了操作处理。

    【讨论】:

      【解决方案5】:

      通过添加这个来创建会话 javax.servlet.http.HttpSession session = request.getSession();

      
      try{ 
       javax.servlet.http.HttpSession session = request.getSession();
          // Validate Captcha 
          String userCaptcha = request.getParameter("captcha"); 
          Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME); 
          if (!captcha.isCorrect(userCaptcha)) { 
              errorMsgs.add("Please input the correct Captcha value."); 
          } 
      } catch (RuntimeException e) { 
          ... 
      } 
      

      【讨论】:

      • 我们期望什么值 session.getAttribute(Captcha.NAME);回来?
      【解决方案6】:

      这一行

       (Captcha) session.getAttribute(Captcha.NAME);
      

      暗示在处理这个特定请求之前会话应该已经存在,因此我想知道在发送原始表单之前你应该进行一些初始化。这应该由您正在使用的框架指定。

      例如,您可能有一个初始 serlvet,

       creates the image, figures out the value of Capcha.Name
       creates the session 
       session.setAttribute(Capcha.NAME, theName)
       emit the html (or forward() to a JSP)
      

      您可以在 JSP 中完成这一切,或者您可以将您的 servlet 转发到一个 JSP。

      您是否可以检查一下这个 catcha 库的使用示例?

      【讨论】:

      • @djna:在发送原始表单之前如何初始化?
      • @djna:我正在使用 Simple Captcha,simplecaptcha.sourceforge.net/index.html,但他们只在 jsp 中说明了一个示例。我真的需要把它转换成servlet。
      猜你喜欢
      • 2013-05-29
      • 2011-07-29
      • 2012-06-06
      • 1970-01-01
      • 2011-12-25
      • 2014-12-08
      • 2014-05-18
      相关资源
      最近更新 更多