解决流只能读一次的问题,getInputStream() has already been called for this request

场景:在aop的日志中想获取 post请求的json数据时报错,因为在后台 控制器的接口中流已经读取了,导致日志这里获取就会报错,需要重写请求的 getInputStream  getReader,然后配置一个过滤器

1、requestWrapper



public class StreamWrapper extends HttpServletRequestWrapper{

    public String _body;

    public StreamWrapper(HttpServletRequest request) throws IOException {
        super(request);
        StringBuffer sBuffer = new StringBuffer();
        BufferedReader bufferedReader = request.getReader();
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            sBuffer.append(line);
        }
        _body = sBuffer.toString();

    }

    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(_body.getBytes());
        return new ServletInputStream() {
            @Override
            public int read() {
                return byteArrayInputStream.read();
            }

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

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

            @Override
            public void setReadListener(ReadListener listener) {

            }
        };
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

}

2、定义一个过滤器



public class StreamFilter implements Filter {

    private  final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(
            Arrays.asList("/api/file/upload")));

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;

        if(request instanceof HttpServletRequest) {
            HttpServletRequest servletRequest = (HttpServletRequest) request;
            String requestURI = servletRequest.getRequestURI();
            if (ALLOWED_PATHS.contains(requestURI)){
                chain.doFilter(servletRequest,response);
            }else {
                requestWrapper = new StreamWrapper(servletRequest);
                //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。
                // 在chain.doFiler方法中传递新的request对象
                chain.doFilter(requestWrapper, response);
            }
        }

    }

    @Override
    public void destroy() {

    }
}

3、springboot配置过滤器



@Configuration
public class StreamConfig {

    @Value("${stream.enabled}")
    private String enabled;

    @Value("${stream.excludes}")
    private String excludes;

    @Value("${stream.urlPatterns}")
    private String urlPatterns;

    @Bean
    public FilterRegistrationBean StreamRegistration() {
        FilterRegistrationBean streamBean = new FilterRegistrationBean();
        streamBean.setDispatcherTypes(DispatcherType.REQUEST);
        streamBean.setFilter(new StreamFilter());
        streamBean.addUrlPatterns(urlPatterns);
        streamBean.setName("StreamFilter");
        streamBean.setOrder(Integer.MAX_VALUE);
        Map<String, String> initParameters = new HashMap<>(16);
        initParameters.put("excludes", excludes);
        initParameters.put("enabled", enabled);
        streamBean.setInitParameters(initParameters);
        return streamBean;
    }

}

4、yml文件

stream:
  # 过滤开关
  enabled: true
  # 排除链接(多个用逗号分隔)
  excludes: /api/file/*,/api/file/upload
  # 匹配链接
  urlPatterns: /api/*

上一篇:git部署出现的问题


下一篇:ModuleNotFoundError: No module named ‘skopt‘