getInputStream() has already been called for this request

getInputStream() has already been called for this request

使用场景:通过request能获取到一次body中的值,有时候我们需要多次获取body中的值的需求,因此需要对流再次封装再次传递

问题原因:在controller中我们通过@RequestBody注解来获取前端传过来的json数据,这里已经使用了一次request来获取body中的值。再次通过request获取body中的值,就会报错。

1.重写自定义XssHttpServletRequestWrapper

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    public String _body;

    public XssHttpServletRequestWrapper(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.自定义过滤器Filter

public class XssFilter implements Filter {
    @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) {
            requestWrapper = new XssHttpServletRequestWrapper((HttpServletRequest) request);
        }
        //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。
        // 在chain.doFiler方法中传递新的request对象
        if(requestWrapper == null) {
     
       chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }

    @Override
    public void destroy() {

    }
}

3…在配置文件进行配置

@Configuration
public class MyWebConfig implements WebMvcConfigurer {
    @Bean
    public FilterRegistrationBean filterRegist() {
        FilterRegistrationBean frBean = new FilterRegistrationBean();
        frBean.setFilter(new XssFilter());
        frBean.addUrlPatterns("/*");
        return frBean;
    }
}

提醒一下 : 如果你进行文件导入时使用了MultiPartFile 这个组件来上传文件,还是会报 getInputSteam()has already exists的异常。所以你只需要将上传文件的那个请求进行过滤就可以了

4.过滤器修改如下

public class XssFilter implements Filter {

	//配置接口过滤
	private  final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(
			Arrays.asList("/uploadSingleFile")));

	@Override
	public void init(FilterConfig config) throws ServletException {
	}

	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 XssHttpServletRequestWrapper(servletRequest);
				//获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。
				// 在chain.doFiler方法中传递新的request对象
				chain.doFilter(requestWrapper, response);
			}
		}
	}

	@Override
	public void destroy() {
	}

}

原文链接:https://www.jianshu.com/p/c2c84563b7a8

你可能感兴趣的:(java,filter,request)