zoukankan      html  css  js  c++  java
  • 使HttpServletRequest中getReader()和getInputStream()可重复使用

    一、 背景

    有时候我们的请求是post,但我们又要对参数签名,这个时候我们需要获取到body的信息,但是当我们使用*HttpServletRequestgetReader()getInputStream()获取参数后,后面不管是框架还是自己想再次获取body已经没办法获取。当然也有一些其他的场景,可能需要多次获取的情况。

    可能抛出类似以下的异常

    java.lang.IllegalStateException: getReader() has already been called for this request
    

    二、spring中的ContentCachingRequestWrapper

    spring中的ContentCachingRequestWrapper提供了getContentAsByteArray()方法用来多次读取body。
    getContentAsByteArray()消费了InputStream来缓存请求体。导致该方法不能多次使用getReader()getInputStream()。所以该方法并不通用。

    三、 自定义扩展

    1. 扩展HttpServletRequest

    创建一个自定义实现HttpServletRequest的类,步骤如下

    1.1. 创建一个自定义类

    需要继承HttpServletRequestWrapper
    并且写一个构造函数来缓存body数据

        public class CustomHttpServletRequest extends HttpServletRequestWrapper {
    
        private byte[] cachedBody;
    
        public CustomHttpServletRequest(HttpServletRequest request) throws IOException {
            super(request);
            InputStream is = request.getInputStream();
            this.cachedBody = StreamUtils.copyToByteArray(is);
        }
    }
    
    

    1.2. 重写getReader()

    @Override
    public BufferedReader getReader() throws IOException {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedBody);
        return new BufferedReader(new InputStreamReader(byteArrayInputStream));
    }
    

    1.3. 重写getInputStream()

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new CachedBodyServletInputStream(this.cachedBody);
    }
    

    CachedBodyServletInputStream参考下面步骤

    2. 实现ServletInputStream

    创建一个继承了ServletInputStream的类

    public class CachedBodyServletInputStream extends ServletInputStream {
        private InputStream cachedBodyInputStream;
    
        public CachedBodyServletInputStream(byte[] cachedBody) {
            this.cachedBodyInputStream = new ByteArrayInputStream(cachedBody);
        }
    
       
        @Override
        public boolean isFinished() {
            try {
                return cachedBodyInputStream.available() == 0;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return false;
        }
    
       
        @Override
        public boolean isReady() {
            return true;
        }
    
        @Override
        public void setReadListener(ReadListener readListener) {
            throw new UnsupportedOperationException();
        }
    
        @Override
        public int read() throws IOException {
            return cachedBodyInputStream.read();
        }
    }
    

    3. 创建一个Filter加入到容器中

    既然要加入到容器中,可以创建一个Filter,然后加入配置
    我们可以简单的继承OncePerRequestFilter然后实现下面方法即可。

    @Override
        protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
            CustomHttpServletRequest customHttpServletRequest =
                    new CustomHttpServletRequest(httpServletRequest);
            filterChain.doFilter(customHttpServletRequest, httpServletResponse);
        }
    

    然后添加该Filter加入即可

    由于本人才疏学浅,若有错误遗漏之处,望指出,以免误导其他同学。
  • 相关阅读:
    svn实现共享文件夹/文件或svn文件夹/文件链接
    插件的“动态替换”
    Swagger启动报错 swagger error creating bean with name documentationPluginsBoostrapper
    观察者模式的几种实现
    python flask 蓝图 多模块开发
    免安装版nginx,启动报错如下:./sbin/nginx: error while loading shared libraries: libpcre.so.0: cannot open shared object file: No such file or directory
    IDEA 支持JDK1.8的-parameters
    电脑自动开机+自动输入密码
    【小练习】立方体旋转
    消除if...else的十种方法
  • 原文地址:https://www.cnblogs.com/daochang/p/15525132.html
Copyright © 2011-2022 走看看