`

关于jetty和webx对于HttpServletResponse getWriter和getOutputStream的处理

    博客分类:
  • java
 
阅读更多

这个异常经过在jetty的一个简单程序的测试验证,确定问题及分析如下:


这个程序在使用response输出结果时,先调用response的getWriter获得PrintWrite对象后输出内容,然后再调用getOutputStream方法获得outputStream对象后输出二进制内容,然后就跑出上面那个异常了。

这两个方法在jetty容易中是这么处理:
org.eclipse.jetty.server.Response继承自j2ee里面的HttpServletResponse.java类
org.eclipse.jetty.server.Response.java类里面

    public ServletOutputStream getOutputStream() throws IOException
    {
        if (_outputState!=NONE && _outputState!=STREAM)    如果状态为WRITER状态,则抛出异常
            throw new IllegalStateException("WRITER");

        _outputState=STREAM;         把response状态改为STREAM流状态
        return _connection.getOutputStream();
    }

  public PrintWriter getWriter() throws IOException
    {
        if (_outputState!=NONE && _outputState!=WRITER)  如果状态为STREAM,则抛出异常
            throw new IllegalStateException("STREAM");

        /* if there is no writer yet */
        if (_writer==null)
        {
            /* get encoding from Content-Type header */
            String encoding = _characterEncoding;

            if (encoding==null)
            {
                /* implementation of educated defaults */
                if(_mimeType!=null)
                    encoding = null; // TODO getHttpContext().getEncodingByMimeType(_mimeType);

                if (encoding==null)
                    encoding = StringUtil.__ISO_8859_1;

                setCharacterEncoding(encoding);
            }

            /* construct Writer using correct encoding */
            _writer = _connection.getPrintWriter(encoding);
        }
        _outputState=WRITER;             把response状态改为WRITER状态,
        return _writer;
    }

也就是说在j2ee,web应用里面不能同时打开PrintWriter和OutputStream,否则就是抛出上面那个异常。

jetty的response里面有三种状态:
    public static final int
        NONE=0,  未调用getPrintWriter和getOutputStream之前的默认状态
        STREAM=1,  二进制流状态  调用getOutputStream之后的状态
        WRITER=2;   字符流状态
  

解决方法:
   1.在应用中只使用一个,要么都用getPrintWriter,要么都用getOutputStream。
   2.在webx 中的com.alibaba.citrus.service.requestcontext.buffered.impl.BufferedResponseImpl.java类中有下面这么解决方案:
  
    /**
     * 取得输出流。
     * 
     * @return response的输出流
     * @throws IOException 输入输出失败
     */
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (stream != null) {
            return stream;
        }

        if (writer != null) {
            // 如果getWriter方法已经被调用,则将writer转换成OutputStream
            // 这样做会增加少量额外的内存开销,但标准的servlet engine不会遇到这种情形,
            // 只有少数servlet engine需要这种做法(resin)。
            if (writerAdapter != null) {
                return writerAdapter;
            } else {
                log.debug("Attampt to getOutputStream after calling getWriter.  This may cause unnecessary system cost.");
                writerAdapter = new WriterOutputStream(writer, getCharacterEncoding());
                return writerAdapter;
            }
        }

        if (buffering) {
            // 注意,servletStream一旦创建,就不改变,
            // 如果需要改变,只需要改变其下面的bytes流即可。
            if (bytesStack == null) {
                bytesStack = new Stack<ByteArrayOutputStream>();
            }

            ByteArrayOutputStream bytes = new ByteArrayOutputStream();

            bytesStack.push(bytes);
            stream = new BufferedServletOutputStream(bytes);

            log.debug("Created new byte buffer");
        } else {
            stream = super.getOutputStream();
        }

        return stream;
    }

    /**
     * 取得输出字符流。
     * 
     * @return response的输出字符流
     * @throws IOException 输入输出失败
     */
    @Override
    public PrintWriter getWriter() throws IOException {
        if (writer != null) {
            return writer;
        }

        if (stream != null) {
            // 如果getOutputStream方法已经被调用,则将stream转换成PrintWriter。
            // 这样做会增加少量额外的内存开销,但标准的servlet engine不会遇到这种情形,
            // 只有少数servlet engine需要这种做法(resin)。
            if (streamAdapter != null) {
                return streamAdapter;
            } else {
                log.debug("Attampt to getWriter after calling getOutputStream.  This may cause unnecessary system cost.");
                streamAdapter = new PrintWriter(new OutputStreamWriter(stream, getCharacterEncoding()), true);
                return streamAdapter;
            }
        }

        if (buffering) {
            // 注意,servletWriter一旦创建,就不改变,
            // 如果需要改变,只需要改变其下面的chars流即可。
            if (charsStack == null) {
                charsStack = new Stack<StringWriter>();
            }

            StringWriter chars = new StringWriter();

            charsStack.push(chars);
            writer = new BufferedServletWriter(chars);

            log.debug("Created new character buffer");
        } else {
            writer = super.getWriter();
        }

        return writer;
    }


  所以在我们自己的应用中就不要再调用完j2ee的原生response的getPrintWriter之后再调用原生的getOutputStream(),或者调用原生的response的getOutputStream之后再调用getPrintWriter。
 

<!--[endif]-->

  • 大小: 127.7 KB
分享到:
评论

相关推荐

    jetty-6.1.26.zip

    Jetty是一款轻量级、高性能的Java Web服务器和Servlet容器,与Tomcat相似,它为开发和部署Web应用程序提供了一种高效的选择。Jetty在设计上注重灵活性和可扩展性,使得它在处理HTTP协议、WebSocket协议以及部署各种...

    jetty所需jar包

    8. **jetty-webapp.jar**:处理Web应用程序的部署和管理,支持WAR文件的部署和解压。 9. **jetty-jndi.jar**:如果需要JNDI(Java Naming and Directory Interface)支持,例如在EJB环境中,这个jar包是必要的。 ...

    jetty和eclpise集成jar包

    7. **热部署**:Jetty集成的一大优点就是支持热部署,即修改了代码后,无需重启服务器,改动就能立即生效,这对于开发和调试非常方便。 8. **Maven集成**:如果你的项目使用Maven构建,可以配置Jetty Maven Plugin...

    jetty6.1.6-2

    以下是一些关于Jetty和其lib目录中的关键知识点: 1. **Servlet容器**:Jetty作为Servlet容器,负责加载和管理Servlet类,处理HTTP请求,并将响应返回给客户端。Servlet是Java中用于开发Web应用的标准接口。 2. **...

    Java Eclipse ee集合jetty和配置

    Eclipse EE 集合 Jetty 和配置 Eclipse 是一个功能强大且流行的集成开发环境(Integrated Development Environment,IDE),提供了许多插件和工具来支持各种编程语言和技术。其中,Eclipse EE(Enterprise Edition...

    jetty各个版本下载

    但是,对于新项目或需要最新特性的项目,推荐使用更现代的版本,如Jetty 9或10,这些版本提供了更多的性能优化和安全更新。 3. **Jetty的下载** 要下载Jetty,你可以访问其官方网站`...

    Jetty和tomcat比较.docx

    ### Jetty和Tomcat的比较 #### 相同点 - **Servlet引擎**: Tomcat和Jetty都是基于Java的Servlet容器,支持标准的servlet规范和JavaEE的规范。这意味着开发者可以在这些容器中部署和运行Java Web应用。 #### 不同...

    jetty 9.4.9

    3. **jetty 容器.txt**:这个文本文件可能包含了关于如何配置和使用Jetty容器的指南或信息,包括启动参数、配置文件设置以及如何部署Web应用程序等内容。对于新手来说,这是一个很好的参考资料。 4. **jetty-...

    jetty 8及依赖包

    Jetty 8在设计时特别强调了性能和可扩展性,它使用了Java NIO(New I/O)API来处理网络通信,相比于传统的基于BIO( Blocking I/O)的服务器,NIO能更好地处理高并发场景。NIO允许单个线程服务多个连接,通过选择器...

    jetty-all.jar

    Jetty-all.jar是一个集合了众多Jetty组件的综合性JAR文件,它的主要目的是为了方便开发者在项目中快速引入和使用Jetty服务器。Jetty是一个开源的HTTP服务器和Servlet容器,它以其轻量级、高性能和易用性而受到广泛...

    WebX入门指南示例程序

    WebX支持声明式和编程式的事务管理,可以轻松处理多数据库操作的事务一致性问题。 10. **示例程序详解**: 提供的“test”文件可能包含了一个简单的WebX示例程序,包括控制器、模型、视图和配置文件等。通过分析...

    jetty.jar,jetty-sslengine.jar,jetty-util.jar

    jetty-sslengine.jar包含了处理SSL/TLS连接的类和方法,使Jetty能够处理基于SSL的请求,支持数字证书,实现服务器与客户端之间的安全通信。这使得开发人员可以轻松地在Jetty上搭建安全的Web服务,满足诸如电子商务...

    jetty嵌入式实例

    Jetty是一款轻量级、高性能的Java Web服务器和Servlet容器,它被广泛应用于各种规模的项目,特别是作为嵌入式服务器使用。...通过理解和实践这个实例,开发者可以更深入地掌握Jetty和JSON处理的技巧。

    jetty-6.1.26官方正式版本.zip

    7. **性能优化**:Jetty以其高效的线程模型和异步I/O而闻名,这使得它在处理大量并发请求时表现出色。 8. **嵌入式使用**:Jetty的一个独特优势是它可以被嵌入到其他Java应用程序中,使得服务器功能可以直接集成到...

    Jetty启动和JSP验证

    此外,设置合适的错误页面(如`error.jsp`)可以帮助捕获和处理运行时错误。 通过上述步骤,你可以成功地在Jetty服务器上启动并验证JSP。这对于理解和实践Java Web开发的基本流程非常有帮助。在实际开发中,你可能...

    Jetty的简单使用示例

    Jetty是一款轻量级、高性能的Java Web服务器和Servlet容器,它被广泛用于开发、测试和部署Web应用程序。本示例将带你了解如何简单地使用Jetty,通过一个Maven项目来实现。以下是对该主题的详细解释: 1. **Jetty...

    how tomcat works和jetty-src和tomcat7-src

    【标题】"how tomcat works和jetty-src和tomcat7-src" 提及了三个关键概念:Tomcat的工作原理、Jetty源代码以及Tomcat 7的源代码。这些是Java Web服务器领域的核心元素,主要涉及到如何处理HTTP请求、部署Web应用...

    jetty 6 指南书

    Jetty 6 指南书是一本详细讲解 Jetty 6.x 版本的专著,由陈汝烨撰写,旨在填补网络上关于 Jetty 新颖、系统性资料的空白,推动 Jetty 在国内的普及。这本书不仅介绍了 Jetty 作为 Web 容器的基本功能,还深入探讨了...

    myeclipse中jetty和svn检出的插件

    在MyEclipse中集成Jetty和SVN检出的插件,可以极大地优化开发流程,使开发者能够便捷地进行项目部署和团队协作。 首先,让我们详细了解一下Jetty。Jetty是一个开源的Servlet容器,它支持最新的Servlet和JSP标准,...

Global site tag (gtag.js) - Google Analytics