查找使用servlet过滤器将内容插入响应的示例

mat*_*der 33 java tomcat6 servlet-filters

我一直在搜索net和stackoverflow,以获取使用servlet过滤器将内容插入响应的示例,但只能找到捕获/压缩输出和/或更改标头的人的示例.我的目标是在所有HTML响应的结束</ body>之前附加一大块HTML.

我正在研究扩展HttpServletResponseWrapper的解决方案,以使用我自己的PrintWriter,然后覆盖其上的write方法.在write方法中,我存储了最后7个字符,看它是否等于关闭body标签,然后我写了我的HTML块加上关闭的body标签,然后继续对文档的其余部分进行正常的写操作.

我觉得有人必须已经解决了这个问题,而且可能比我更优雅.我很欣赏如何使用servlet过滤器将内容插入响应的任何示例.

更新

回应评论,我也试图从http://www.oracle.com/technetwork/java/filters-137243.html实现CharResponseWrapper .这是我的代码:

PrintWriter out = response.getWriter();
CharResponseWrapper wrappedResponse = new CharResponseWrapper(
        (HttpServletResponse)response);

chain.doFilter(wrappedRequest, wrappedResponse);
String s = wrappedResponse.toString();

if (wrappedResponse.getContentType().equals("text/html") &&
        StringUtils.isNotBlank(s)) {
    CharArrayWriter caw = new CharArrayWriter();
    caw.write(s.substring(0, s.indexOf("</body>") - 1));
    caw.write("WTF</body></html>");
    response.setContentLength(caw.toString().length());
    out.write(caw.toString());
}
else {
    out.write(wrappedResponse.toString());
}

out.close();
Run Code Online (Sandbox Code Playgroud)

我也在包装请求,但该代码有效,不应影响响应.

mat*_*der 44

我正在使用的代码库在处理响应时调用getOutputStream方法而不是getWriter,因此其他答案中包含的示例没有帮助.这是一个更完整的答案,适用于OutputStream和PrintWriter,如果写入器被访问两次,甚至可以正确地出错.这是源自使用JAVAX.SERVLET.FILTER的优秀示例,DUMP REQUEST和RESPONSE.

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class MyFilter implements Filter
{
    private FilterConfig filterConfig = null;

    private static class ByteArrayServletStream extends ServletOutputStream
    {
        ByteArrayOutputStream baos;

        ByteArrayServletStream(ByteArrayOutputStream baos)
        {
            this.baos = baos;
        }

        public void write(int param) throws IOException
        {
            baos.write(param);
        }
    }

    private static class ByteArrayPrintWriter
    {

        private ByteArrayOutputStream baos = new ByteArrayOutputStream();

        private PrintWriter pw = new PrintWriter(baos);

        private ServletOutputStream sos = new ByteArrayServletStream(baos);

        public PrintWriter getWriter()
        {
            return pw;
        }

        public ServletOutputStream getStream()
        {
            return sos;
        }

        byte[] toByteArray()
        {
            return baos.toByteArray();
        }
    }

    public class CharResponseWrapper extends HttpServletResponseWrapper
    {
        private ByteArrayPrintWriter output;
        private boolean usingWriter;

        public CharResponseWrapper(HttpServletResponse response)
        {
            super(response);
            usingWriter = false;
            output = new ByteArrayPrintWriter();
        }

        public byte[] getByteArray()
        {
            return output.toByteArray();
        }

        @Override
        public ServletOutputStream getOutputStream() throws IOException
        {
            // will error out, if in use
            if (usingWriter) {
                super.getOutputStream();
            }
            usingWriter = true;
            return output.getStream();
        }

        @Override
        public PrintWriter getWriter() throws IOException
        {
            // will error out, if in use
            if (usingWriter) {
                super.getWriter();
            }
            usingWriter = true;
            return output.getWriter();
        }

        public String toString()
        {
            return output.toString();
        }
    }

    public void init(FilterConfig filterConfig) throws ServletException
    {
        this.filterConfig = filterConfig;
    }

    public void destroy()
    {
        filterConfig = null;
    }

    public void doFilter(
            ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException
    {
        CharResponseWrapper wrappedResponse = new CharResponseWrapper(
                (HttpServletResponse)response);

        chain.doFilter(request, wrappedResponse);
        byte[] bytes = wrappedResponse.getByteArray();

        if (wrappedResponse.getContentType().contains("text/html")) {
            String out = new String(bytes);
            // DO YOUR REPLACEMENTS HERE
            out = out.replace("</head>", "WTF</head>");
            response.getOutputStream().write(out.getBytes());
        }
        else {
            response.getOutputStream().write(bytes);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 一个重要的注意事项:您需要使用HttpServletResponse.setContentLength方法根据您的响应主体更改来更新响应头,否则不匹配可能会导致客户端上的未知行为. (16认同)
  • @snowindy 非常重要的注意事项!但是,我必须调整内容长度 _before_ 进行实际替换(即在调用 response.getOutputStream().write() 之前),否则它会被简单地忽略。 (2认同)
  • 此解决方案不再可用(至少在此发布的表单中)。ByteArrayServletStream 需要实现两个抽象方法,init 函数不能再被执行,因为它是最终的。 (2认同)

iTe*_*ech 18

您需要实现HttpServletResponseWrapper来修改响应.请参阅此文档过滤器的基本知识,它有一个转换响应的示例,它比您想要的更多

编辑

我尝试过一个带响应过滤器的简单Servlet,它运行得很好.Servlet输出字符串Test,响应过滤器将字符串附加到它上面filtered,最后当我从浏览器运行时,我得到了Test filtered你想要实现的响应.

我在Apache Tomcat 7上运行了以下代码,它没有例外.

Servlet的:

protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {

   response.getWriter().println("Test");

}
Run Code Online (Sandbox Code Playgroud)

过滤:

public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {

    System.out.println("BEFORE filter");
    PrintWriter out = response.getWriter();
    CharResponseWrapper responseWrapper = new CharResponseWrapper(
            (HttpServletResponse) response);

    chain.doFilter(request, responseWrapper);

    String servletResponse = new String(responseWrapper.toString());

    out.write(servletResponse + " filtered"); // Here you can change the response


    System.out.println("AFTER filter, original response: "
            + servletResponse);

}
Run Code Online (Sandbox Code Playgroud)

CharResponseWrapper(完全如文章)

public class CharResponseWrapper extends HttpServletResponseWrapper {
    private CharArrayWriter output;

    public String toString() {
        return output.toString();
    }

    public CharResponseWrapper(HttpServletResponse response) {
        super(response);
        output = new CharArrayWriter();
    }

    public PrintWriter getWriter() {
        return new PrintWriter(output);
    }
}
Run Code Online (Sandbox Code Playgroud)

web.xml中

<servlet>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>TestServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>TestServlet</servlet-name>
    <url-pattern>/TestServlet</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>TestFilter</filter-name>
    <filter-class>MyFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>TestFilter</filter-name>
    <url-pattern>/TestServlet/*</url-pattern>
</filter-mapping>
Run Code Online (Sandbox Code Playgroud)

  • 我在chain.doFilter(wrappedRequest,wrappedResponse)中得到了异常; 看起来底层代码正在调用getOutputStream(),它使用相同的编写器. (3认同)
  • 在这个例子之后,我得到了这个异常 - java.lang.IllegalStateException:已经为此响应调用了getWriter() (2认同)