Captcha servlet 导致 java.lang.IllegalStateException: PWC3999: 提交响应后无法创建会话

发布于 2024-08-18 05:10:28 字数 1752 浏览 6 评论 0原文

我正在使用 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 上创建会话?我该如何解决这个问题?

非常感谢。

I am creating a CAPTCHA input using SimpleCaptcha, and did validation of the Captcha input. I am created a captcha input with the following codes.

HTML Code:

<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 Code :

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

However I kept getting this error:

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

How do I create a session on my servlet? How can I resolve this issue?

Thank you very much.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

七月上 2024-08-25 05:10:28

提交响应后无法创建会话

异常消息非常清楚。有非法国家的手段。当响应已经提交时,您不能再设置/更改响应标头。当标头已发送到客户端时,将提交响应。这是一个无法返回的点。

每当输出流被直接刷新(输入)时,就会提交响应。当您向响应写入超过 2K 数据(具体取决于服务器配置)、手动执行 flush() 或执行 sendRedirect() 调用时,就会发生这种情况。

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

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

servlet 验证码的 Servlet.service() 抛出异常

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

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

Cannot create a session after the response has been committed

The exception message is pretty clear. There's means of an illegal state. You cannot set/change the response headers anymore when the response is already been committed. A response is committed when the headers are already been sent to the client side. This is a point of no return.

The response will be committed whenever the outputstream has been flushed (in)directly. That can happen when you write more than 2K to the response (depends on server config however), or did flush() manually, or did a sendRedirect() call.

Whenever the session needs to be created, the server needs to set a cookie in the response header so that it can identify the particular client and associate it with a HttpSession instance in the server memory. But that's not possible if the response is already committed, hence this exception.

Back to the root cause of this problem:

Servlet.service() for servlet Captcha threw exception

It is the servlet with the servlet-name of Captcha which caused this problem. You need to check/debug the entire request-response chain to see which servlets/filters are all invoked and which of them might have committed the response before the Captcha servlet was able to create the session. I can't help you more further as this information is missing in your topicstart.

At least, in the as far given code example, I see that you're unnecessarily calling response.getWriter(). I am not sure how the real world code look like, maybe you've stripped some lines, but chances are that you're actually writing to it and that might be the root cause of the problem. If you write too much or did a flush on it, then the resopnse will be committed. Do not write to the response inside a Servlet which is supposed to be a controller. There you normally use the JSP for. Or if it is for debugging purposes, use the stdout (System.out.println()) or a Logger.

冷了相思 2024-08-25 05:10:28

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

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

实际上,代码正在将图像文件写入响应(通常大于默认的 2k)。

因此,您暂时可以使用 StickyCaptcha 或检查代码并解决问题。

The offending code is in nl.captcha.servlet.SimpleCaptchaServlet Servlet. If you change it to StickyCaptcha the problem will go away but specifically the following are the offending lines in SimpleCaptcha Servlet.

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

Actually the code is writing the image file to response (which is usually greater than default 2k).

So for the time being you can use the StickyCaptcha or checkout the code and fix the issue.

因为看清所以看轻 2024-08-25 05:10:28

将此行:移动

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

  //...
}

这应该有帮助。

Move this line:

HttpSession session = request.getSession(true);

to be first statement in doPost method.

protected void doPost(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {

  HttpSession session = request.getSession(true);

  response.setContentType("text/html;charset=UTF-8");

  //...
}

This should help.

妖妓 2024-08-25 05:10:28

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

Seems, that you already sent the header to the client before handling the post. If you create a session, the server needs to send the session ID to the client. This is usually done by sending a cookie. I suppose you check your code for whether you execute the action handling before you send anything back to the client.

束缚m 2024-08-25 05:10:28

通过添加此创建会话
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) { 
    ... 
} 

create session by adding this
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) { 
    ... 
} 
卸妝后依然美 2024-08-25 05:10:28

此行

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

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

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

 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 转发到一个。

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

This line

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

implies that the session should already exist before this particular request is being processed, hence I wonder is there is some initialisation you are supposed to do before sending your original form. This should be specified by the framework your are using.

For example you might have an initial serlvet that

 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)

You could do that all in a JSP, or you could have your servlet forward to one.

Are there any examples of usage of this catcha library you could examine?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文