未使用过滤器和 ByteArrayOutputStream 写入响应

Posted

技术标签:

【中文标题】未使用过滤器和 ByteArrayOutputStream 写入响应【英文标题】:response not being written using filter and ByteArrayOutputStream 【发布时间】:2014-10-13 00:37:20 【问题描述】:

我有以下过滤器:

@WebFilter( filterName = "myfilter" )
public class WebCacheFilter implements Filter 
    @Override
    public void init( FilterConfig filterConfig ) 

    @EJB
    AppExceptionLogger logger;

    @Override
    public void doFilter( ServletRequest req, ServletResponse res, final FilterChain chain )
    throws IOException, ServletException 
        final HttpServletRequest request = ( HttpServletRequest )req;
        final HttpServletResponse response = ( HttpServletResponse )res;
        execute( new StreamAction<ByteArrayOutputStream>() 
            @Override
            public void doAction( ByteArrayOutputStream stream ) throws Exception 
                chain.doFilter( request, new ProxiedServletResponse( response, stream ) );
                response.getOutputStream()
                    .write( stream.toByteArray() );
            
         );
    

    @Override
    public void destroy() 

    private void execute( StreamAction<ByteArrayOutputStream> action ) throws IOException 
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try 
            action.doAction( stream );
         catch ( Exception e ) 
            logger.logInternal( e );
         finally 
            stream.close();
        
    

在 web.xml 中被映射为

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <filter-mapping>
        <filter-name>myfilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

ProxiedServletResponse 类来自这里:https://github.com/FagnerMartinsBrack/Servlet-GZIP-Compression/blob/95f4bac01e5037ea403f502819d3e74f66ef1ad0/src/main/java/com/fagnerbrack/servlet/gzip/proxy/ProxiedServletResponse.java

下面是test.jsp文件内容:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Página de teste</title>
    <!-- Descrição do sistema -->
    <meta name="description" content="">
    <!-- Ajusta o conteúdo de acordo com o tamanho da tela em aparelhos mobile -->
    <meta name="viewport" content="width=device-width">
  </head>
  <body>
    test page
  </body>
</html>

当我尝试访问\webapp\test.jsp 文件时,浏览器不会打印任何内容。看来response.getOutputStream().write( stream.toByteArray() ); 部分不起作用。这是为什么呢?

注意:如果您尝试访问像 /static/js/jquery.js 这样的 javascript 文件,它会正确加载。只有 JSP 文件没有加载。

注意 2:baos.toByteArray() 部分中,对于 JSP 文件,ByteArrayOutputStream 的长度为 0 (!!!)

【问题讨论】:

【参考方案1】:

JSP 写入getWriter(),而不是getOutputStream()。在您的getWriter() 中,您将ByteArrayInputStream 包装在PrintWriter 中。 PrintWriter 有一个 8K 字符缓冲区。 JSP 明显小于 8K 字符。在获得写入的byte[] 之前,您永远不会flush()ing PrintWriter 的缓冲区,因此它永远不会写入包装的ByteArrayInputStream

你需要冲洗母狗。替换

chain.doFilter(request, new ProxiedServletResponse(response, stream));
response.getOutputStream().write(stream.toByteArray());

通过

HttpServletResponse proxiedResponse = new ProxiedServletResponse(response, stream);
chain.doFilter(request, proxiedResponse);
proxiedResponse.flushBuffer();
response.getOutputStream().write(stream.toByteArray());

【讨论】:

这个 sh1t 是在 Java 8 中简化的吗? 这部分,没有。不过,我确实想知道您的 sn-p 中的 executeStreamAction 在这里有什么用处。 是的,我意识到我不需要关闭流,因为它是由我创建的并且仅在此过滤器生命周期中使用。在某些情况下,我使用该执行/操作模式来关闭流,而不是使用 try-with-resource。

以上是关于未使用过滤器和 ByteArrayOutputStream 写入响应的主要内容,如果未能解决你的问题,请参考以下文章

自定义 Symfony2 过滤器未使用自定义树枝标签触发

FIREBASE 警告:使用未指定的索引。您的数据将在客户端下载和过滤

bigQuery 和 GA-Premium 集成:从 GA 中的未过滤视图导出数据时,如何在 bigQuery 中使用 IP 过滤器(以排除内部流量)

使用两个未绑定的文本框按日期范围过滤表单记录

Android BLE,扫描开始,找到设备但未连接过滤器(ESP32 和三星)

在路径更改时使用过滤器时未呈现路径模型