使用 HttpServletRequestWrapper 重复读取 HttpServletRequest(多次读取 request 请求)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HeatDeath/article/details/80338051

今天尝试在切面中读取 request 请求,校验请求的参数,解析异常则报错

但是,在 切面读取了一次 request 后,再到 controller 的时候,request 就变成了空的

找了一圈找到这种方法,通过继承 HttpServletRequestWrapper ,来操作 HttpServletRequest

package xxxxx;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.util.Collections;

/**
 * Author:  heatdeath
 * Date:    2018/5/15
 * Desc:
 */
@Aspect
@Component
public class RestServiceValidReqAndHandleExc {
    private static final Logger logger = LoggerFactory.getLogger(RestServiceValidReqAndHandleExc.class);

    @Pointcut("@annotation(web.aspect.annotation.AnnForValidReqAndHandleExc)")
    public void parseRequestPointcut() {
    }

    @Around("parseRequestPointcut()")
    public Object parseHttpRequest(ProceedingJoinPoint joinPoint) {
        HttpServletRequest request = (HttpServletRequest) joinPoint.getArgs()[0];
        ResettableStreamHttpServletRequest wrappedRequest = new ResettableStreamHttpServletRequest(request);
        try {
            wrappedRequest.setCharacterEncoding("utf-8");
            String bodyStr = HttpServletRequestUtil.readHttpServletRequestBody(wrappedRequest);
            if (StringUtils.isEmpty(bodyStr))
                return ResultMessageUtil.getErrorResultMessage(new ResultMessage(), ErrorNumConsts.PARAM_ERROR,
                        "请求数据不能为空!");
        } catch (Exception e) {
            System.out.println(ExceptionUtils.getExceptionStackTrace(e));
            return ResultMessageUtil.getErrorResultMessage(new ResultMessage(), ErrorNumConsts.PARAM_ERROR,
                    "解析请求数据错误!");
        }
        try {
            wrappedRequest.resetInputStream();
            Object[] args = Collections.singletonList(wrappedRequest).toArray();
            return joinPoint.proceed(args);
        } catch (Throwable t) {
            logger.error(ExceptionUtils.getExceptionStackTrace(t));
            return ResultMessageUtil.getErrorResultMessage(new ResultMessage(), ErrorNumConsts.OPERATION_ERROR,
                    "操作失败,请再次尝试!");
        }
    }

    private static class ResettableStreamHttpServletRequest extends
            HttpServletRequestWrapper {

        private byte[] rawData;
        private HttpServletRequest request;
        private ResettableServletInputStream servletStream;

        ResettableStreamHttpServletRequest(HttpServletRequest request) {
            super(request);
            this.request = request;
            this.servletStream = new ResettableServletInputStream();
        }


        void resetInputStream() {
            servletStream.stream = new ByteArrayInputStream(rawData);
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            if (rawData == null) {
                rawData = IOUtils.toByteArray(this.request.getReader());
                servletStream.stream = new ByteArrayInputStream(rawData);
            }
            return servletStream;
        }

        @Override
        public BufferedReader getReader() throws IOException {
            if (rawData == null) {
                rawData = IOUtils.toByteArray(this.request.getReader());
                servletStream.stream = new ByteArrayInputStream(rawData);
            }
            return new BufferedReader(new InputStreamReader(servletStream));
        }


        private class ResettableServletInputStream extends ServletInputStream {

            private InputStream stream;

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

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

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

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        }
    }

}

参考资料:

1、request.getInputStream()只能获取一次的问题
https://blog.csdn.net/zly9923218/article/details/52120920

2、解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法
https://my.oschina.net/vernon/blog/363693

3、拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.
https://blog.csdn.net/beflyabot/article/details/78053130


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页