springboot在过滤器filter 获取request中post的数据和获取response的数据问题

项目中需要在filter处理一些post请求的数据和response的响应数据,比如数据解密,重复提交验证

 

在项目中,涉及到了内外网,且内外网不是通过端口映射来同步数据而是多加了一层网闸,考虑到用户体验问题,进行了一个请求保存,通过网闸将本次请求传到内网再请求一次,达到内外网数据一致(涉及了ID预设问题)


request和response的流只能获取一次,如果在filter中获取了以后,controller会报错(类似于Miss body),而response会没有响应值

 

解决方法:

request请求处理:

需要定义一个继承HttpServletRequestWrapper类的RequestWrapper

public class RequestWrapper extends HttpServletRequestWrapper {
    private byte[] body;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = this.toByteArray(request.getInputStream());
    }

    private byte[] toByteArray(ServletInputStream inputStream) throws IOException {
        ByteArrayOutputStream out=new ByteArrayOutputStream();
        byte[] buffer=new byte[1024*4];
        int n=0;
        while((n= inputStream.read(buffer))!=-1){
            out.write(buffer,0,n);
        }
        return out.toByteArray();
    }

    @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 boolean isFinished() {
                return false;
            }

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

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }

    public byte[] getBody() {
        return body;
    }

    public void setBody(byte[] data){
        body=data;
    }
}

request请求处理:

需要定义一个继承HttpServletRequestWrapper类的RequestWrapper

public class ResponseWrapper extends HttpServletResponseWrapper {
    private ByteArrayOutputStream byteArrayOutputStream;
    private ServletOutputStream servletOutputStream;
    private PrintWriter writer;



    public ResponseWrapper(HttpServletResponse response) {
        super(response);
        byteArrayOutputStream=new ByteArrayOutputStream();
        servletOutputStream=new WapperedOutputStream(byteArrayOutputStream);
        writer = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream,StandardCharsets.UTF_8));
    }

    @Override
    public ServletOutputStream getOutputStream(){
        return servletOutputStream;
    }

    @Override
    public PrintWriter getWriter() {
        return writer;
    }

    @Override
    public void flushBuffer(){
        if (servletOutputStream!=null){
            try {
                servletOutputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (writer!=null)
            writer.flush();
    }

    @Override
    public void reset() {
        byteArrayOutputStream.reset();
    }

    public String getResponseData(String charset) throws IOException {
        flushBuffer();
        byte[] bytes = byteArrayOutputStream.toByteArray();
        return new String(bytes,charset);
    }

    private class WapperedOutputStream extends ServletOutputStream{

        private ByteArrayOutputStream bos;

        public WapperedOutputStream(ByteArrayOutputStream stream){
            bos = stream;
        }

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

        @Override
        public void setWriteListener(WriteListener writeListener) {

        }

        @Override
        public void write(int b){
            bos.write(b);
        }
    }

    public byte[] getContent(){
        flushBuffer();
        return byteArrayOutputStream.toByteArray();
    }
}

在过滤器中将ServletRequest替换成RequestWrapper

在过滤器中将ServletResponse替换成ResponseWrapper

public class RequestWrapperFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
        ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) servletResponse);
        //获取post的值
        String body = IOUtils.toString(requestWrapper.getBody(), "UTF-8");
        //中间处理操作省略,生成newBody
        String newBody= .......//省略代码
        //修改body以后,想将修改body的值传入到RequestWrapper,如果没有修改,则可以无视,我这里要预设id
        requestWrapper.setBody(newBody);

        
        filterChain.doFilter(requestWrapper,responseWrapper);
        byte[] content = responseWrapper.getContent();
        //获取response的值
        String responseData = IOUtils.toString(content, "UTF-8");
        
        //注意 此处是servletResponse 不是responseWrapper,写responseWrapper的话 依旧响应不了
        ServletOutputStream outputStream = servletResponse.getOutputStream();
        outputStream.write(content);
        outputStream.flush();
        outputStream.close();
    }
}

同理,若后续需要用到post数据的话,类似于aop保存日志之类的,也是需要用RequestWrapper对request进行包装,然后从requesWrapper中获取数据

 RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
 String body = IOUtils.toString(requestWrapper.getBody(), "UTF-8");

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值