将 tomcat 7.0.59 升级到 7.0.61:提交响应后无法创建会话

Upgrade tomcat 7.0.59 to 7.0.61 : Cannot create a session after the response has been committed

提问人:user1391606 提问时间:10/11/2015 最后编辑:user1391606 更新时间:2/18/2016 访问量:1461

问:

我们正在从 Tomcat 7.0.59 升级到 7.0.61 并收到以下错误。

仅当通过 Apache 代理(无 SSL)传递时,才会发生此错误。

当从浏览器(没有 Apache 代理)调用 Tomcat 上下文时,它可以正常工作。

有没有人遇到过相同/类似的问题?

我们确实查看了更新日志(https://tomcat.apache.org/tomcat-7.0-doc/changelog.html),但我们在 Tomcat 7.0.61 中找不到任何解释此行为的更改

SEVERE: Servlet.service() for servlet [CaptchaServlet] in context with path [/cw] threw exception
java.lang.IllegalStateException: Cannot create a session after the response has been committed
    at org.apache.catalina.connector.Request.doGetSession(Request.java:3008)
    at org.apache.catalina.connector.Request.getSession(Request.java:2384)
    at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:897)
    at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:909)
    at be.servlet.CaptchaServlet.doGet(CaptchaServlet.java:127)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.filters.ExpiresFilter.doFilter(ExpiresFilter.java:1175)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
    at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:190)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

有关守则为:

    public void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

    HttpSession session = req.getSession();

    Captcha captcha = getNumberCaptcha(_width, _height, 5, Color.black);

    session.setAttribute(NAME, captcha);

    resp.setHeader("Cache-Control", "private,no-cache,no-store");
    resp.setContentType("image/png");


    // See https://wiki.apache.org/tomcat/FAQ/KnownIssues#ImageIOIssues
    // Wrap insite MyImageIOOutputStream
    ImageIO.write(captcha.getImage(), "png", new MyImageIOOutputStream(resp.getOutputStream()));

    resp.getOutputStream().flush();
    resp.getOutputStream().close();

}

在开始说它是 ImageIO 之前,我们确实使用了 https://wiki.apache.org/tomcat/FAQ/KnownIssues#ImageIOIssues 上指定的 MyImageIOOutputStream。

我们甚至尝试将图像从 File 加载到字节数组中,并在共振中发送字节数组(因此没有使用 ImageIO),但问题仍然相同。

Java 会话 Tomcat

评论


答:

0赞 Codo 10/12/2015 #1

令人惊讶的是,此错误发生在 Tomcat 7.0.61 中,但在 7.0.59 中却没有。该错误基本上表示您在发送 HTTP 响应标头后正在创建会话。这是一个问题,因为会话需要 cookie,并且 cookie 在 HTTP 响应标头中传输。所以现在发送cookie为时已晚。

假设 CaptchaServlet 是您的代码,最简单的解决方案是在 servlet 中写入任何输出之前创建会话 ()。然后,您可以安全地使用任何 servlet 容器。getSession()

评论

0赞 user1391606 10/13/2015
我不认为问题与Java代码有关。如前所述,绕过 het 代理可以解决问题(但在 PROD 环境中当然没有选项)。很奇怪。
0赞 Codo 10/13/2015
如果您的代码开始编写输出,然后启动会话(并因此更新 cookie),则一切都取决于输出是已缓冲还是已发送到下游。因此,代理确实可以改变行为(特别是如果您从 HTTP 协议切换到 AJP 协议,这通常是使用代理)。此外,修复 Java 代码将在任何情况下可靠地消除此错误。
0赞 user1391606 10/15/2015
嗨,我添加了相关代码。如果你发现有什么不对劲的地方,我会很高兴听到这一切!但我没有看到它(如前所述,这段代码在过去 5 年一直在 PROD(proxy-SSL)上运行,并且从未出现任何问题。
0赞 Codo 10/15/2015
如果第 127 行是 ,那么这确实很奇怪。您的代码具有使用会话的正确顺序。这个 servlet 是直接调用的,还是内部转发的结果?HttpSession session = req.getSession();
0赞 user1391606 10/17/2015
嗨,servlet 是直接调用的。
0赞 Jorge Aranda 10/19/2015 #2

我确认我有和你一样的问题(在我的特殊情况下,7.0.62 vs 7.0.59)。如果 Tomcat 版本为 7.0.59,我的应用程序在 apache 代理后面工作正常,但如果我在代理后面使用 7.0.62,我的跟踪与您相同。

在我看来,我们应该尽快向Tomcat报告

评论

0赞 user1391606 10/19/2015
嗨,是的,但我想我们需要调试信息来为报告提供一些正文。我不知道你什么时候可以做一些调试(见上面的评论),但在这里需要几周的时间,因为我们正在做另一个项目。