news 2026/7/28 16:45:40

SpringBoot拦截器读取流后不能再读取(详解)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot拦截器读取流后不能再读取(详解)
在SpringBoot的拦截器中通过流 ( request.getInputStream() ) 的方式读取body中传来的数据会导致controller接收不到值。

这个问题其实就是一个流读取的问题,众所周知在Java中input流只能读取一次,主要原因是通标记的方法来判断流是否读取完毕(读取位 -1就是流读取完毕)解决这个问题我能想到两种方式

  1. 通过修改标记的方式 ( inputstream.markSupported() 方法可以判断这个流是否支持 mark 和 reset 方法。他们分别是标记 和 重新定位流。)
  2. 将流赋值给一个 byte[] 数组,或者其他变量保存起来。下载读取流时就调用这个数组就行。
第一种方法

再回到问题上来我们可以先使用第一种方法判断 requet 中的inputStream 是否支持标记和重新定位。因为这种方式实现起来比较简单。无需考虑太多。

@OverridepublicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsIOException{booleanb=request.getInputStream().markSupported();System.out.println(b);}// 输出结果为 false

上述代码会返回一个 false 那么很明显,request 中的 input 流是不支持标记和重新定位的。

第二种方法

我们再考虑第二种方法,我们需要一个变量保存这个流。并且还要保证再过滤器中和controller中都要拿到这个变量。直接定义一个全局变量获取修改传值方式,都是可以的。全局变量这种方式我就不演示了。下面是改变传值方式的 demo

publicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsIOException{ServletInputStream inputStream1=request.getInputStream();// 各种对 inputStream1 处理的操作...Object obejct=inputStream1;request.setAttribute("Params",obejct);}

这样就可以再controller那边就可以直接获取 Attribute 中的值。

但是!这样有很大的局限性,例如: 我已经写好了大多数的controller方法体。这时再改用这种方式传值。对于开发人员是一种莫大的痛苦 -_- 于是通过不屑的百度查询到另一种方法 一一一 改写HttpServletRequestWrapper方法。为什么是这个方法?因为他实现了 HttpServletRequest 这个接口。也是我们拦截器接收的 request 要求的类型。首先我们先看一张图。**注意 filter 和 inteceptor 中间。**


通过上方这个图我们可以知道,在 Filter 和 Inteceptor 中间有一层Servlet。而Servlet就是提交request的地方。所以我们要重写HttpServletRequest方法只能在Servlet之前。也就是filter 中。下面就是直接上代码了

  1. 重写 HttpServletRequest
packagecom.xqw.kyg.util;importjava.io.BufferedReader;importjava.io.ByteArrayInputStream;importjava.io.IOException;importjava.io.InputStreamReader;importjavax.servlet.ReadListener;importjavax.servlet.ServletInputStream;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletRequestWrapper;importorg.springframework.util.StreamUtils;publicclassMyHttpServletRequestWrapperextendsHttpServletRequestWrapper{privatebyte[]requestBody=null;//用于将流保存下来publicMyHttpServletRequestWrapper(HttpServletRequest request)throwsIOException{super(request);requestBody=StreamUtils.copyToByteArray(request.getInputStream());}@OverridepublicServletInputStreamgetInputStream(){finalByteArrayInputStream bais=newByteArrayInputStream(requestBody);returnnewServletInputStream(){@Overridepublicintread(){returnbais.read();// 读取 requestBody 中的数据}@OverridepublicbooleanisFinished(){returnfalse;}@OverridepublicbooleanisReady(){returnfalse;}@OverridepublicvoidsetReadListener(ReadListener readListener){}};}@OverridepublicBufferedReadergetReader()throwsIOException{returnnewBufferedReader(newInputStreamReader(getInputStream()));}}
  1. 编写Filter
packagecom.xqw.kyg.filter;importcom.xqw.kyg.util.MyHttpServletRequestWrapper;importorg.springframework.stereotype.Component;importjavax.servlet.*;importjavax.servlet.http.HttpServletRequest;importjava.io.IOException;@ComponentpublicclassHttpServletRequestReplacedFilterimplementsFilter{@Overridepublicvoiddestroy(){}@OverridepublicvoiddoFilter(ServletRequest request,ServletResponse response,FilterChain chain)throwsIOException,ServletException{ServletRequest requestWrapper=null;if(requestinstanceofHttpServletRequest){requestWrapper=newMyHttpServletRequestWrapper((HttpServletRequest)request);}if(requestWrapper==null){chain.doFilter(request,response);}else{chain.doFilter(requestWrapper,response);}}@Overridepublicvoidinit(FilterConfig arg0)throwsServletException{}}
到此代码编写就完成了。你现在可以在 过滤器 中读取inputstream数据controller中也可以获取到了。其实代码并不是特别困难。主要是出现BUG能及时的想到原因,和提供解决方案。

扩展内容
github
个人博客

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/28 16:42:47

AngularJS通过$sce输出html的方法

【问题描述】 AngularJS的强大之处之一就是他的数据双向绑定功能----->ng-bind和针对form的ng-model 但在我们的项目当中会遇到这样的情况,后台返回的数据中带有各种各样的html标签 AngularJS输出html的时候,浏览器并不解析这些html标签 通过api&…

作者头像 李华
网站建设 2026/7/28 16:40:53

Serverless安全实战:从TAR依赖漏洞到10步纵深防御体系构建

1. 项目概述:一次真实的Serverless安全危机复盘 上周三凌晨,我被一阵急促的告警电话惊醒。监控显示,我们一个核心的Serverless函数突然出现大量异常调用,CPU使用率飙升至100%,日志里充斥着奇怪的路径遍历错误。经过紧急…

作者头像 李华
网站建设 2026/7/28 16:38:19

NBM5100A评估板与PIC18LF4525的低功耗物联网电源管理方案

1. NBM5100A评估板的核心功能解析NBM5100A评估板是安世半导体推出的一款专为纽扣电池应用场景设计的电源管理解决方案。这款评估板的核心价值在于解决了物联网设备中常见的两大痛点:电池寿命短和峰值电流供应不足。在实际工程应用中,CR2032这类纽扣电池的…

作者头像 李华
网站建设 2026/7/28 16:37:34

可完美替代Everspin的Netsol串行接口MRAM芯片高性能存储方案

串行接口MRAM芯片是基于CMOS工艺集成磁存储技术的新型非易失性存储器件,凭借独特的磁性隧道结(MTJ)工作机制,兼具高速读写、超长寿命、稳定存储等多重优势,现已成为工业存储领域的优选方案。其中Netsol Parallel异步接…

作者头像 李华
网站建设 2026/7/28 16:36:34

降重工具测评:达不达标怎么判定?

降重工具测评:达不达标怎么判定? 你现在多半是这种状态:论文查重报告一出来,红字一片,重复率或者 AI 率高得吓人,然后打开搜索框搜"降重工具哪个好用",结果跳出来一大堆,…

作者头像 李华
网站建设 2026/7/28 16:36:25

Agentic AI实战:从概念到生产级智能体的架构设计与工程实践

最近在跟进几个企业级AI项目的落地,发现一个明显的趋势:单纯调用大模型API已经不够用了。客户的需求越来越复杂,从简单的问答、摘要,逐渐转向需要多步骤推理、自主调用工具、并能持续学习的智能体(Agent)。…

作者头像 李华