解决Filter中request.getInputStream()后Controller中读取不到的流的问题
2016-05-23 12:51:41  By: dwtedx

最近一直在研究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参数一定要传我们自定义的才行、不然又会出问题的

若资源对你有帮助、浏览后有很大收获、不妨小额打赏我一下、你的鼓励是维持我不断写博客最大动力

想获取DD博客最新代码、你可以扫描下方的二维码、关注DD博客微信公众号(ddblogs)

或者你也可以关注我的新浪微博、了解DD博客的最新动态:DD博客官方微博(dwtedx的微博)

如对资源有任何疑问或觉得仍然有很大的改善空间、可以对该博文进行评论、希望不吝赐教

为保证及时回复、可以使用博客留言板给我留言: DD博客留言板(dwtedx的留言板)

感谢你的访问、祝你生活愉快、工作顺心、欢迎常来逛逛


快速评论


技术评论

    • peakmuma@163.com 2016-10-22 20:29:15  3 评  | 回复

      构造函数里body内容的生成过程实在是太啰嗦了: 1.先把inputStream转换成reader 2.reader转换成“utf-8”的string 3.string又根据“utf-8”转成byte[] 实际上可以直接从inputStream得到byte[]。 给你推荐两个现成的实现: 第一种:依赖springframework.core包 body = StreamUtils.copyToByteArray(request.getInputStream()); 第二种:依赖apache的commons.io包 body = IOUtils.toByteArray(request.getInputStream()); 你这篇文章基本上都是引用别人的思路,不知道为啥没给出参考资料的链接。


DD记账
top
+