欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-02-02 18:35:28
...

场景:在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/*

相关标签: restful http java