【问题标题】:How can I peek into a Mesage from a Filter?如何查看来自过滤器的消息?
【发布时间】:2012-03-04 18:30:33
【问题描述】:

我尝试使用javax.servlet.Filter 来查看消息。

public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
     BufferedReader reader = request.getReader();
     if ( reader.markSupported() ) {
         reader.mark( contentLen );
     }
     String content = reader.readLine();

     // search some pattern

     if ( reader.markSupported() ) {
         reader.reset();
     }
     chain.doFilter( request, response );
}

最终收到请求的 servlet 抛出这个异常:

java.lang.IllegalStateException: getReader() has already been called for this request

根据 javadoc,这是正确的行为。

我的问题是如何读取输入流的内容?

我也试过ServletInputStream is = request.getInputStream();

【问题讨论】:

  • 能否克隆请求,然后查看克隆?

标签: java spring servlets servlet-filters


【解决方案1】:

未测试,但您可能可以

  • 从请求输入流中读取所有字节并将它们写入字节数组,
  • 在这个字节数组上构造一个缓冲读取器来读取你想要的过滤器,
  • 构造一个覆盖getInputStream() 的HttpServletRequestWrapper 以在字节数组上返回一个流,
  • 将此包装器传递给过滤器链。

【讨论】:

  • 谢谢,复制似乎是唯一的方法。
  • 这会打开一个简单的OutOfMemoryError 漏洞漏洞。黑客只需发送一个大于服务器可用堆的请求体,即可完全关闭服务器。看看 Apache Commons FileUpload 如何通过部分存储在内存中并保留在临时磁盘上来处理大文件上传。或者只是根据具体的功能要求寻找不同的解决方案。
  • @BalusC:有趣。 Tomcat 使用设置为 2 兆字节的 maxPostSize 来避免常规请求正文解析的这个问题。我猜 OP 应该做同样的事情,一旦读取的字节数超过 X MB,就会抛出异常。我想知道自动将 JSON 编码的请求正文转换为对象的 Web 框架是否具有这种最大值,或者它们是否存在相同的漏洞。
  • 如果一个自尊的API,它应该这样做。
【解决方案2】:

ServletRequest.getInputStream() 和 ServletRequest.getReader() 是非此即彼的,所以如果其中一个已经被调用,另一个将失败。你可以使用一个简单的 try-catch 来解决这个问题:

try {
    request.getInputStream();
} catch (IllegalStateException e) {
    // someone already called getReader(), so use it instead
    request.getReader();
}

注意! 没有指定流或读取器应该是可重置的,因此如果您消耗掉它的任何字节,它们将不再可用于链中的任何过滤器或 servlet。

【讨论】:

  • 很难告诉所有这些 JSP 和其他 servlet 这样做。不,这不是一个真正可行的“解决方法”,当真正以某种方式实现时,它可能还会弄乱字符编码。
【解决方案3】:

遵循@JB Nizet 的方法导致了以下代码:

public class HttpServletRequestCopy extends HttpServletRequestWrapper {

    private final byte[]       buffer;

    private ServletInputStream sis;

    private BufferedReader     reader;

    public byte[] getBuffer() {
        return buffer;
    }

    public HttpServletRequestCopy( HttpServletRequest request) throws IOException {
        super( request );
        final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        copyStream( request.getInputStream(), byteArrayOutputStream );
        buffer = byteArrayOutputStream.toByteArray();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        if ( reader == null ) {
            String characterEncoding = this.getCharacterEncoding();
            if ( characterEncoding == null ) {
                reader = new BufferedReader( new InputStreamReader( this.getInputStream() ) );
            }
            else {
                reader = new BufferedReader( new InputStreamReader( this.getInputStream(), characterEncoding ) );
            }
        }
        return reader;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if ( sis == null ) {
            final ByteArrayInputStream bais = new ByteArrayInputStream( buffer );
            sis = new ServletInputStream() {
                @Override
                public int read() throws IOException {
                    return bais.read();
                }
            };
        }
        return sis;
    }

    private void copyStream( InputStream input, OutputStream output) throws IOException {
        final byte[] bytes = new byte[ 1024 ];
        int length;
        while ( (length = input.read( bytes )) != -1 ) {
            output.write( bytes, 0, length );
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-23
    • 1970-01-01
    相关资源
    最近更新 更多