欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  技术分享

解决Filter中request.getInputStream()后Controller中读取不到的流的问题

程序员文章站 2022-02-16 11:56:01
...

最近一直在研究Spring MVC写App接口的框架的东西、其实的都搞得差不多咯、最后要做一个Filter、然后在Filter中主要验证一下请求有没有被篡改、校验请求是否合法、自己实现了Spring的OncePerRequestFilter来验证、由于很久没有写Java EE相关的东西了

都忘了getInputStream()只有读一次、验证之后一直提示400 Bad Request The request sent by the client was syntactically incorrect、最后又通过HandlerInterceptorAdapter去处理、发现还是这个错误、后来查了很多很多资料才回忆起来

原来流只能读一次、 读了就没有了、为了后面的代码还能够取得流、 我们应该还需要将其写出去才行、然后又是一番网上的资料查阅、最后用HttpServletRequestWrapper搞出来了、必须笔记一下、分享给更多朋友


BodyReaderHttpServletRequestWrapper.java

public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

	private final byte[] body;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
    }

    @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();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }

}


HttpHelper.java

/**
 * 获取请求Body
 *
 * @param request
 * @return
 */
public static String getBodyString(ServletRequest request) {
    StringBuilder sb = new StringBuilder();
    InputStream inputStream = null;
    BufferedReader reader = null;
    try {
        inputStream = request.getInputStream();
        reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
        String line = "";
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return sb.toString();
}


Filter.Java

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
		throws ServletException, IOException {
			
    // 防止流读取一次后就没有了, 所以需要将流继续写出去
    ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
    String json = HttpHelper.getBodyString(requestWrapper);
            
    System.out.println(json);

	filterChain.doFilter(requestWrapper, response);
}


最后需要注意的是在doFilter的时候、request参数一定要传我们自定义的才行、不然又会出问题的