码恋 码恋

ALL YOUR SMILES, ALL MY LIFE.

目录
解决使用@Requestbody时报错Stream closed
/    

解决使用@Requestbody时报错Stream closed

场景

框架Spring boot,使用@Requestbody注解接收参数时报错,具体错误信息如下:

I/O error  while reading input message; nested exception is java.io.IOException: Stream closed

分析

当时在做一个给外部系统调用的接口,增加了验证签名的拦截器,验签时通过流获取Requestbody里面的数据。但是这个流这能使用一次,并且只能通过流获取。故,在使用@Requestbody注解再次获取参数时,会出现 java.io.IOException: Stream closed

解决思路

在使用流时,先读取流,再把这个流写出去。

步骤

不废话,直接上代码。

  • 重写HttpServletRequestWrapper
public class RequestWrapper extends HttpServletRequestWrapper {
    private final String body;

    public RequestWrapper(HttpServletRequest request) {
        super(request);
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        InputStream inputStream = null;
        try {
            inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[1024];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        body = stringBuilder.toString();
    }

    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
            @Override
            public int read() {
                return byteArrayInputStream.read();
            }
        };

    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    public String getBody() {
        return this.body;
    }

}
  • 增加一个WebFilter
@WebFilter(urlPatterns = "/*",filterName = "channelFilter")
public class ChannelFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(servletRequest instanceof HttpServletRequest) {
            requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
        }
        if(requestWrapper == null) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            filterChain.doFilter(requestWrapper, servletResponse);
        }
    }

    @Override
    public void destroy() {

    }
}
  • 开启Servle组件扫描

在Spring boot启动类上加上@ServletComponentScan注解。

  • 使用上面的RequestWrapper获取body
RequestWrapper requestWrapper = new RequestWrapper(request);
        String body = requestWrapper.getBody();

好了,问题解决。


标题:解决使用@Requestbody时报错Stream closed
作者:wangning1018
地址:https://aysaml.com/articles/2019/05/15/1557888345020.html