日期:2014-05-16  浏览次数:20557 次

jetty和ajaxanywhere有冲突

有同事反映jetty下部署的应用程序有问题,而这个应用部署在tomcat则没有问题,这个应用使用了ajaxanywhere,同组的人判断jetty和ajaxanywhere不兼容,到底那里出了问题呢?还要从源码看起。

?

org.ajaxanywhere.BufferResponseWrapper类包装了原始的HttpServletResponse,并重写了getWriter和getOutputStream方法:

    public PrintWriter getWriter() throws IOException {
        if (writerBuffer == null) {
            writerBuffer = new StringWriter();
            pw = new PrintWriter(writerBuffer);
        }
        return pw;
    }

    public ServletOutputStream getOutputStream() throws IOException {
        if (streamBuffer == null) {
            streamBuffer = new ByteArrayOutputStream();
            sos = new ServletOutputStream() {
                public void write(int b) throws IOException {
                    streamBuffer.write(b);
                }

                public void write(byte b[]) throws IOException {
                    streamBuffer.write(b);
                }

                public void write(byte b[], int off, int len) throws IOException {
                    streamBuffer.write(b, off, len);
                }
            };
        }
        return sos;
    }

?在tomcat下发现只调用了getWriter方法,而在jetty下则同时调用了getWriter和getOutputStream方法,为什么会有这种差别呢?

?

问题出在jetty中的一个类:org.eclipse.jetty.server.Dispatcher,这个类的forward方法有问题,和tomcat中的对应的方法逻辑不一样,jetty在处理完forward调用后,有以下的代码:

                if (baseRequest.getResponse().isWriting())
                {
                    try {response.getWriter().close();}
                    catch(IllegalStateException e) 
                    { 
                        response.getOutputStream().close(); 
                    }
                }
                else
                {
                    try {response.getOutputStream().close();}
                    catch(IllegalStateException e) 
                    { 
                        response.getWriter().close(); 
                    }
                }

?tomcat在处理完forward调用后,有以下的代码:

                try {
                    PrintWriter writer = response.getWriter();
                    writer.close();
                } catch (IllegalStateException e) {
                    try {
                        ServletOutputStream stream = response.getOutputStream();
                        stream.close();
                    } catch (IllegalStateException f) {
                        ;
                    } catch (IOException f) {
                        ;
                    }
                } catch (IOException e) {
                    ;
                }

?

tomcat中的逻辑是先关闭writer,如果出错了,再尝试关闭outputStream

jetty中的逻辑是,如果baseRequest中有writer,则先关闭writer,如果没有writer,则先关闭outputStream

而BufferResponseWrapper调用getWriter或getOutputStream并不会触发被包装的HttpServletResponse创建底层的writer或outputStream,所有jetty中永远都会先关闭outputStream,这就会调用BufferResponseWrapper中的getOutputStream方法了。

?

解决的办法是用Tomcat中相关的代码替换Jetty相关的代码