【问题标题】:Writers and OutputStreams in Java EE applications and filtersJava EE 应用程序和过滤器中的写入器和输出流
【发布时间】:2011-06-13 12:16:31
【问题描述】:

我最近遇到了以下异常...

java.lang.IllegalStateException: 无法获取 Writer,因为 OutputStream 已在使用中

我了解异常的性质;即代码可以使用 Writer 或 OutputStream 但不能在同一个请求中同时使用。堆栈中的代码应该如何处理已经存在的情况?或者是否有一种设计/架构模式可以首先避免这个问题?

示例;考虑一个装饰请求输出的 3rd 方过滤器,它会获得一个 OutputStream。需要与 Writer 一起工作的过滤器或 servlet 如何“知道” OutputStream 已经打开并且应该关心?反过来也是一个有效的 Q。

【问题讨论】:

    标签: java servlets jakarta-ee servlet-filters


    【解决方案1】:

    我将尝试解决您的示例中提出的更具体的问题:

    考虑一个装饰请求输出的第 3 方过滤器,它会获得一个 OutputStream。需要与 Writer 一起工作的过滤器或 servlet 如何“知道” OutputStream 已经打开并且应该关心?

    Servlet API 也不允许在填充响应时同时使用 Writer 和 OutputStream,如ServletResponse.getWriter() method 的 API 文档中所述:

    可以调用此方法或 getOutputStream() 来写入正文,而不是两者。

    如果过滤器(第三方或其他)想要写入响应,尤其是在 servlet 生成响应之后,它应该假设

    • servlet 已使用 Writer 或 OutputStream 来填充响应。
    • servlet 会调用 Writer 或 OutputStream 对象上的 close() 方法。

    为了解决这个问题,过滤器必须创建一个 HttpServletResponseWrapper 实例,将其传递到下游的 servlet 进行填充,再次读回它,然后填充实际的容器管理的 HttpServletResponse 对象。

    如果过滤器首先填充响应(在进一步处理请求之前),上述内容也适用。它应该对实际的 HttpServletResponse 对象执行填充,向下游传递一个包装器,然后将包装器的内容写入实际对象。

    【讨论】:

      【解决方案2】:

      设计方法非常简单:

      • 不要在 JSP 中使用 Java 代码 (scriptlets)。这会隐式触发getWriter()
      • 当您要转发到 JSP 时,不要向 Servlet 中的响应写入任何内容。

      换句话说,如果你坚持 MVC 的思想,基本上没有什么好担心的。

      【讨论】:

      • 这是个好建议,但它不处理过滤器需要修改应用程序生成的输出的情况。
      • @Stephen:嗯,我没有这样解释这个问题。但是,如果您的想法属实,那么只需在 HttpServletResponseWrapper 实现的两个 getter 中添加两个布尔属性和一个 if 检查和一个布尔切换。
      【解决方案3】:

      另一种方法是设计Filter,使其根据web.xml 中的配置设置使用Writer 或OutputStream。然后根据过滤请求的Servlet配置Filter

      【讨论】:

        猜你喜欢
        • 2011-06-10
        • 1970-01-01
        • 2017-09-07
        • 2014-08-16
        • 2015-01-02
        • 2014-10-13
        • 1970-01-01
        • 2012-03-23
        • 2016-12-04
        相关资源
        最近更新 更多