zoukankan      html  css  js  c++  java
  • servlet读取请求参数后流失效的问题

    在用reset接口的时候,常常会使用request.getInputStream()方法,但是流只能读取一次,一旦想要加上一个过滤器用来检测用户请求的数据时就会出现异常。

    在过滤器中通过流读取出用户post提交过来的数据,这是流已经读取了一次,那么该流就已经作废了,所以在contorller再次读取用户请求的数据时就会抛出异常。
    解决方法
     
    方法一:
     
    参见:http://www.cnblogs.com/jiangxinnju/p/5709378.html
    简单说一下原理,其实就是通过自定义的HttpServletRequestWrapper 备份一下流的数据,自定义HttpServletRequestWrapper 调用父类request.getInputStream()读取全部数据出来保存在一个byte数组内,当再次获取流数据的时候,自定义的HttpServletRequestWrapper 就会用byte数组重新生成一个新的流。备份的流数据仍然保留在byte数组中。
     
    方法二:
    request.getInputStream()方法只能使用一次,流就会作废了,其实我们还可以通过另一种方式获取用户传输的数据,那就是通过request.getReader()来获取到一个BufferedReader。这里要说一下BufferedReader是缓存流,并且BufferedReader的markSupported方法是返回true,说明BufferedReader是可以标记和回退的流。
     
    BufferedReader中有defaultCharBufferSize属性
     
    static { BufferedReader.defaultCharBufferSize = 8192; BufferedReader.defaultExpectedLineLength = 80; }
     
    这里可以看出缓存大小为8192,也就是8KB大小的缓存,所以我们可以用BufferedReader的标记和重置方法来进行重复读取流。
     
    方法二的性能会比方法一的性能较快,因为BufferedReader只存在一个实例,而不是每次调用都生成。要注意的是通过BufferedReader的标记和重置方法只能读取8KB以内的内容。超过8KB进行重复读取时,将会清空8KB前的缓存,导致标记失效,缓存内容将会丢失。比如:读取了9KB的内容,那么其中前面的1KB的内容将会在缓存中被清除掉,而只缓存了后面的8KB内容,前面的1KB内容被永久清除了,但后面的8KB内容还是能通过标记重置来进行重复读取。 (8KB内容相当于4000字)
     
    方法一也是可以做成缓存流的形式,代替每次生成一个新的实例,这里就不一一介绍。
     
    方法一也是有缺点的,就是遇到文件上传时内存消耗会增加,因为上传的文件也是在request流中的,一旦上传较大的文件,服务器将会内存不足导致宕机。
     
    建议最好使用原生自带的缓存BufferedReader,会更加方便。

    重写request的inputstream方法。。然后在需要部署应用中加上过滤器,在过滤器中加上这个重写的request的方法

    如下:编写filter并在web.xml中配置filter

    @WebFilter(filterName="accessFilter", urlPatterns={
                 "*.do",
         //        "*.jsp",
         //        "/*",
         //        "/layout/*",
         //        "/apply/*",
         //        "/audit/*",
         //        "/authority/*",
         //        "/commonWare/*",
         //        "/contract/*",
         //        "/marketing/*",
         //        "/product/*",
         //        "/project/*",
         //        "/system/*",
         //        "/user/*"
                 })
         public class MyFilter implements Filter {
             //     日志对象
             private static Logger logger = Logger.getLogger(MyFilter.class);
         
             public void init(FilterConfig filterConfig) throws ServletException {
             }
             
             public void destroy() {
             }
         
             public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {
                 HttpServletRequest request = (HttpServletRequest) req;
                 System.out.println("=====+" + req.hashCode());
                 HttpServletResponse response = (HttpServletResponse) res;        
                 if ("POST".equalsIgnoreCase(request.getMethod())) {
                     
                     ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
                     System.out.println("===filter==+" + requestWrapper.hashCode());
         
                     String body = HttpUtil.getBodyString(requestWrapper);
                     System.out.println("AccessFilter="+body);
                     chain.doFilter(requestWrapper, response);
                     return ;
                 }
                 
                 chain.doFilter(req, res);
             }
         }
    public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
    
            private final byte[] body;
    
            public MyHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
                super(request);
                body = HttpUtil.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();
                    }
                };
            }
        }
    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();
        }

    参考:https://www.cnblogs.com/a393060727/p/6141295.html

  • 相关阅读:
    创业者,你有梦想吗?
    中型企业能撑过现金危机
    共享经济与优步(Uber)如何获取监管支持?
    TJX:好买手养成记
    问得更少,获悉更多
    成功创新者该问的问题
    物联网革命的核心是“网”,而不是“物”
    成功领导力的10大关键
    人们抗拒组织变革的十大原因
    李彦宏:PC时代结束
  • 原文地址:https://www.cnblogs.com/flgb/p/10976751.html
Copyright © 2011-2022 走看看