草庐IT

java - 过滤器链 : java. 的 GlassFish 问题 lang.IllegalStateException: PWC3990: getWriter() 已为此响应调用

coder 2024-03-26 原文

我们需要升级旧的 Web 应用程序以在 GlassFish 3 而不是 Tomcat 下运行,以便获得 EAR 部署(选择 Glassfish 是因为它是引用 JEE 6 实现)

不幸的是,很快发现确保用户登录的机制无法正常工作,并提示 getWriter() 已被调用(这很可能是正确的),我无法弄清楚原因。

我们的方法是对完整的 JSP 文件集进行过滤器检查用户是否已登录,如果没有,则使用 filterChain.doFilter(servletRequest, servletResponse); 重定向到登录页面; 。用户状态(包括凭据)存储在 session 范围内的所谓 Controller 对象中,该对象由登录验证 Java 代码设置。


来自 Glassfish 的堆栈跟踪:

java.lang.IllegalStateException: PWC3990: getWriter() has already been called for this response
    at org.apache.catalina.connector.Response.getOutputStream(Response.java:676)
    at org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:205)
    at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:176)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
    at com.XXX.LoggedInToXXXFilter.doFilter(LoggedInToXXXFilter.java:61)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
....

web.xml 片段

<?xml version="1.0"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<description>
    XXX provides a web interface for a given user.
</description>
<display-name>
XXX
</display-name>
<context-param>
    <param-name>javax.faces.CONFIG_FILES</param-name> 
    <param-value>/WEB-INF/online-faces-config.xml</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.ALLOW_JAVASCRIPT</param-name>
    <param-value>true</param-value>
</context-param> 

<listener>
    <listener-class>
        org.apache.myfaces.webapp.StartupServletContextListener
    </listener-class>
</listener>
<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>
    javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.jsf</url-pattern>
</servlet-mapping>

<session-config>
    <!-- idle time in minutes before user is automatically logged out by the container -->
    <session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
    <filter-name>MyFacesExtensionsFilter</filter-name>
    <filter-class>
        org.apache.myfaces.webapp.filter.ExtensionsFilter
    </filter-class>
    <init-param>
        <param-name>maxFileSize</param-name>
        <param-value>1m</param-value>
        <!-- description>Set the size limit for uploaded files.
            Format: 10 - 10 bytes
            10k - 10 KB
            10m - 10 MB
            1g - 1 GB
            </description-->
    </init-param>
</filter>

<!-- extension mapping for adding <script/>, <link/>, and other resource tags to JSF-pages  -->
<filter-mapping>
    <filter-name>MyFacesExtensionsFilter</filter-name>
    <!-- servlet-name must match the name of your javax.faces.webapp.FacesServlet entry -->
    <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

<!-- extension mapping for serving page-independent resources (javascript, stylesheets, images, etc.)  -->
<filter-mapping>
    <filter-name>MyFacesExtensionsFilter</filter-name>
    <url-pattern>/faces/myFacesExtensionResource/*</url-pattern>
</filter-mapping>

<filter>
    <description>Ensure user is logged in</description>
    <filter-name>LoggedInToXXXFilter</filter-name>
    <filter-class>
        com.XXX.servlet.filters.LoggedInToXXXFilter
    </filter-class>
    <init-param>
        <param-name>signon_page</param-name>
        <param-value>/login.jsf</param-value>
    </init-param>
    <init-param>
        <param-name>autologout_page</param-name>
        <param-value>/autologout.jsp</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>LoggedInToXXXFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- filter>
    <filter-name>extensionsFilter</filter-name>
    <filter-class>org.apache.myfaces.component.html.util.ExtensionsFilter</filter-class>
    <init-param>
    <param-name>uploadMaxFileSize</param-name>
    <param-value>100m</param-value>
    </init-param>
    <init-param>
    <param-name>uploadThresholdSize</param-name>
    <param-value>100k</param-value>
    </init-param>
    </filter-->
<!-- filter-mapping>
    <filter-name>extensionsFilter</filter-name>
    <url-pattern>*.jsf</url-pattern>
    </filter-mapping>
    <filter-mapping>
    <filter-name>extensionsFilter</filter-name>
    <url-pattern>/faces/*</url-pattern>
    </filter-mapping-->
<!-- error-page>
    <exception-type>java.lang.IllegalArgumentException</exception-type>
    <location>/WEB-INF/jsp/IllegalArgumentException.jsp</location>
    </error-page-->
<error-page>
    <exception-type>java.lang.RuntimeException</exception-type>
    <location>/WEB-INF/jsp/RuntimeException.jsp</location>
</error-page>
<!-- error-page>
    <exception-type>com.transaxiom.axsWHSweb.struts.action.UserIsNotLoggedInException</exception-type>
    <location>/WEB-INF/jsp/UserIsNotLoggedInException.jsp</location>
    </error-page-->
<error-page>
    <exception-type>
        com.XXX.struts.action.SecurityViolationException
    </exception-type>
    <location>/WEB-INF/jsp/SecurityViolationException.jsp</location>
</error-page>
<error-page>
    <exception-type>
        com.XXX.logic.UncheckedCommunicationException
    </exception-type>
    <location>/WEB-INF/jsp/CommunicationException.jsp</location>
</error-page>
<error-page>
    <exception-type>
        com.XXX.logic.ConnectionNotCreatedException
    </exception-type>
    <location>
        /WEB-INF/jsp/ConnectionNotCreatedException.jsp
    </location>
</error-page>
<!-- error-page>
    <exception-type>com.XXX.logic.UncheckedConnectionNotCreatedException</exception-type>
    <location>/WEB-INF/jsp/ConnectionNotCreatedException.jsp</location>
    </error-page-->
<!-- filter>
    <filter-name>MyFacesExtensionsFilter</filter-name>
    <filter-class>org.apache.myfaces.component.html.util.ExtensionsFilter</filter-class>
    <init-param>
    <param-name>maxFileSize</param-name>
    <param-value>20m</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>MyFacesExtensionsFilter</filter-name>
    <url-pattern>*.faces</url-pattern>
    </filter-mapping-->
</web-app>

来自 LoggedInToXXXFilter.java 的过滤代码:

(堆栈跟踪发生在 filterChain.doFilter(servletRequest, servletResponse) 行中。

public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
        final FilterChain filterChain) throws IOException, ServletException {
    boolean ok = false;
    if (servletRequest instanceof HttpServletRequest) {
        HttpServletRequest request = (HttpServletRequest) servletRequest;

        String servletPath = request.getServletPath();
        if ((servletPath.equals(signOnPage) == true) || servletPath.endsWith(".css") || servletPath.equals(autologoutPage)) {
            ok = true;
        } else {
            Controller controller = Controller.getControllerFromSession(request.getSession(false));
            if ((controller != null) && controller.isSignedOn()) {
                ok = true;
            }

        }
        if (ok) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            // Hop to the sign on page.
            // http://forum.java.sun.com/thread.jspa?threadID=548967&messageID=2676856
            ServletContext servletContext = filterConfig.getServletContext();

            URL url = new URL(new URL(request.getRequestURL().toString()), (request.getContextPath() + signOnPage));
            ((HttpServletResponse) servletResponse).sendRedirect(url.toString());
        }
    } else {
        // Only for http requests
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

一个可能的原因是我们仍然使用我们自己的 JSF 库(带有 Tomahawk 的 MyFaces 1.1.4)吗?


编辑:使用完整(但匿名)的 web.xml 更新了问题。请注意,有很多注释掉的东西。我把它留在里面,以免不小心删除重要信息


编辑:试验了 sun-web-app 配置文件,发现它没有什么不同。有趣的是,登录后,登录页面抛出异常,但我可以手动导航到主页(也是 JSF)并看到另外两个功能正常的页面。除了抛出异常的登录页面外,还有3个页面。

我最初的想法是分离功能是 t-taglib(用于 Tomahawk),但经过快速调查后似乎并非如此,因为一些工作页面使用 Tomahawk 而另一些则没有。


编辑:比较两个 jsp 页面,一个失败了,另一个失败了,没有发现任何明显的差异应该导致这个。正如所指出的那样,Tomahawk 1.1 已经报告了这个错误,而我们使用的是 1.1.3,我现在已经升级到最新的 Apache Myfaces Tomahawk 1.1.9,它似乎已经解决了这个问题(没有 sun-网络应用程序)。

最佳答案

我没有完整的解释(即我不知道 getWriter 在哪里被调用)但这可能是 Jira 中报告的 Tomahawk 1.1.3/MyFaces 1.1.4 中的错误类似 TOMAHAWK-579 的问题或 MYFACES-1310 (根据 Servlet 规范具有相同的 IllegalStateException)。请注意,正如您遇到的那样,此错误似乎与容器有关。

因此,要么尝试使用更新版本的 Tomahawk/MyFaces(参见 compatibility matrix),要么获取 patch对应于 r442340 中的修复并将其应用于Tomahawk的分支1.1.3。后一种选择可能是最简单的选择。至少,这是我会尝试的。

关于java - 过滤器链 : java. 的 GlassFish 问题 lang.IllegalStateException: PWC3990: getWriter() 已为此响应调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2235559/

有关java - 过滤器链 : java. 的 GlassFish 问题 lang.IllegalStateException: PWC3990: getWriter() 已为此响应调用的更多相关文章

  1. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  2. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  3. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  4. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  5. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  6. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  7. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  8. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  9. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  10. ruby-on-rails - 在 Controller 中干净地处理多个过滤器(参数) - 2

    我有一个名为Post的类,我需要能够适应以下场景:如果用户选择了一个类别,则只显示该类别的帖子如果用户选择了一种类型,则只显示该类型的帖子如果用户选择了一个类别和类型,则只显示该类别中该类型的帖子如果用户没有选择任何内容,则显示所有帖子我想知道我的Controller是否不可避免地会因大量条件语句而显得粗糙...这是我解决此问题的错误方法-有谁知道我如何才能做到这一点?classPostsController 最佳答案 您最好遵循“胖模型,瘦Controller”的惯例,这意味着您应该将这种逻辑放在模型本身中。Post类应该能够报告

随机推荐