SpringBoot下解决request请求流重复读取问题的策略

版权申诉
5星 · 超过95%的资源 13 下载量 193 浏览量 更新于2024-09-11 收藏 66KB PDF 举报
在开发过程中,我们可能会遇到一个常见的问题,即在Spring Boot项目中,由于安全需求(如防止SQL注入),我们通常会通过Filter拦截器来对请求流中的JSON数据进行校验。然而,当拦截器处理完请求后,如果后续代码尝试再次从`HttpServletRequest`对象中获取这些校验过的JSON数据时,却发现数据已经不可用。这是因为`HttpServletRequest`的`InputStream`和`Reader`是单次使用的,一旦读取完毕,数据流就被消耗,无法重复读取。 这个问题可以通过自定义一个`HttpServletRequestWrapper`的子类来解决。具体步骤如下: 1. 创建一个新的类,如`BodyReaderHttpServletRequestWrapper`,继承自`HttpServletRequestWrapper`,这是一个包装类,用于提供额外的功能而不会改变原始请求的行为。 2. 在构造函数中,使用`StreamUtils.copyToByteArray()`方法将原始请求的输入流(`InputStream`)复制一份,存储在一个私有byte[]类型的变量`requestBody`中。这样做是为了保留原始数据流,以便后续可以复用。 3. 重写`getInputStream()`方法,创建一个新的`ByteArrayInputStream`,传入`requestBody`作为参数。这个新的流是从复制的字节数组中获取的,而不是原始的输入流。 4. 实现一个自定义的`ServletInputStream`子类,覆盖`read()`方法。在这个方法中,每次读取都从复制的字节流中执行,而不是从原始输入流,从而实现数据的重复读取。 以下是部分关键代码示例: ```java public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private byte[] requestBody; public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); requestBody = StreamUtils.copyToByteArray(request.getInputStream()); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody); return new ServletInputStream() { @Override public int read() throws IOException { // 在这里读取复制的字节流 // ... } }; } } ``` 通过这种方式,每次调用`getInputStream()`或`getReader()`时,实际上是在操作复制的流,从而避免了原始请求流只能读取一次的问题。这种解决方案可以方便地在需要多次使用请求数据的场景下,如校验、解析或处理JSON数据时,确保数据的可用性。