赞
踩
1、问题描述:
spring-boot环境下部分接口使用@RequestBody接收前端传递的复杂json格式数据,在controller中处理完业务逻辑之后,会通过request从流中读取初始请求数据,保存到用户访问日志记录中;当请求进入@RequestBody注解标注的方法之后,一切正常,被标注的复杂对象也获取到了前端传递的数据,但是在后面记录日志读取request输入流时,发现:stream closed,出现了异常(也许此时你会惊讶,what 什么鬼)。
2、原因
经过查找资料发现,spring mvc在处理@RequestBody时,会从request.getInputStream()中读取数据,而该api存在以下特性:
- 1. 一个InputStream对象在被读取完成后,将无法被再次读取,始终返回-1;
-
- 2. InputStream并没有实现reset方法(可以重置首次读取的位置),无法实现重置操作;
也就是说当我图二再次读取流中数据时,此时因为第一次读取完成之后pos指针在末尾,故第二次无法再读取数据(该api也不支持reset pos指针位置)。
3、解决办法
使用HttpServletRequestWrapper来包装HttpServletRequest,在MAPIHttpServletRequestWrapper中初始化读取request的InputStream数据,以byte[]形式缓存在其中,然后在Filter中将request转换为包装过的request;代码如下:
-
- public class MAPIHttpServletRequestWrapper extends HttpServletRequestWrapper {
-
- private final byte[] body; // 报文
-
- public MAPIHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
- super(request);
- body = readBytes(request.getInputStream());
- }
-
- @Override
- public BufferedReader getReader() throws IOException {
- return new BufferedReader(new InputStreamReader(getInputStream()));
- }
-
- @Override
- public ServletInputStream getInputStream() throws IOException {
- final ByteArrayInputStream bais = new ByteArrayInputStream(body);
- return new ServletInputStream() {
-
- @Override
- public int read() throws IOException {
- return bais.read();
- }
- };
- }
-
- /**
- * 获取http输入流
- * @param inputStream
- * @return
- */
- public byte[] readBytes(InputStream inputStream) throws IOException {
-
- ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
- int length=-1;
- byte[] bytes=new byte[1024];
- while((length=inputStream.read(bytes))!=-1){
- byteArrayOutputStream.write(bytes,0,length);
- }
- return byteArrayOutputStream.toByteArray();
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
-
- public class HttpServletRequestReplacedFilter implements Filter {
-
- @Override
- public void destroy() {
-
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain) throws IOException, ServletException {
- ServletRequest requestWrapper = null;
- if(request instanceof HttpServletRequest) {
- requestWrapper = new MAPIHttpServletRequestWrapper((HttpServletRequest) request);
- }
- if(requestWrapper == null) {
- chain.doFilter(request, response);
- } else {
- chain.doFilter(requestWrapper, response);
- }
- }
-
- @Override
- public void init(FilterConfig arg0) throws ServletException {
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
此处感谢网友解决方案:https://blog.csdn.net/With_Her/article/details/82382942
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。