java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > HttpServletRequest.getInputStream()多次读取

如何解决HttpServletRequest.getInputStream()多次读取问题

作者:yxl_num

这篇文章主要介绍了如何解决HttpServletRequest.getInputStream()多次读取问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

HttpServletRequest.getInputStream()多次读取问题

使用POST方法发送数据时,我们习惯于把数据包装成json格式。

有些情况下,我们会在Filter中读取body数据进行数据校验,GET方法获取参数比较简单。

对于POST方法,可使用如下方法从request中获取body参数:

 private String getBody(HttpServletRequest request) throws IOException {
    InputStream in = request.getInputStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(in, Charset.forName("UTF-8")));
    StringBuffer sb = new StringBuffer("");
    String temp;
    while ((temp = br.readLine()) != null) {
        sb.append(temp);
    }
    if (in != null) {
        in.close();
    }
    if (br != null) {
        br.close();
    }
    return sb.toString();
}

注意,这里有了一次request.getInputStream()调用。

但是在测试时,一直报JSON格式不正确的错误。经调查发现,项目中使用了公司基础组件中的Filter,而该Filter中也解析了body。

同时,不出所料,也是通过调用getInputStream()方法获取的。

原来:

因此,当自己写的Filter中调用了一次getInputStream()后,后面再调用getInputStream()读取的数据都为空,所以才报JSON格式不正确的错误。

解决方法

缓存数据

所谓缓存数据,其实就是调用ServletRequestsetAttribute(String s, Object o)来存储数据。

1.获取到body后,直接缓存

String body = getBody(request);
request.setAttribute("body", body);

优点:

方便

缺点:

不能控制第三方Filter

1.其他地方需要使用body时,只需调用getAttribute方法就能获取数据了:

request.getAttribute("body");

HttpServletRequestWrapper包装

public class RequestWrapper extends HttpServletRequestWrapper {
    private final byte[] body;
    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = getBodyStringFromReq(request).getBytes(Charset.forName("UTF-8"));
    }
    public String getBodyString() {
        try {
            return new String(body, "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            return new String(body);
        }
    }
    private String getBodyStringFromReq(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中使用时,FilterChain.doFilter()传入Wrapper对象:

public class TestFilter implements Filter {
    @Override
    public void destroy() {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest)request);
        String body = requestWrapper.getBodyString();
        chain.doFilter(requestWrapper, response);  //传入Wrapper对象
    }
    @Override
    public void init(FilterConfig arg0) throws ServletException {
    }
}

这样,位于后面的Filter就可以拥有唯一一次调用HttpServletRequest.getInputStream()的机会了。

优点:

不影响第三方Filter

缺点:

多写了这么多代码,麻烦了一些

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文