SpringBoot过滤器获取Request的body数据

背景 

       由于在SpringBoot过滤器或者拦截器中,request中getReader()和getInputStream()只能调用一次,到controller里数据就为空了,因此会导致Controller中@RequestBody的参数无法注入而导致 400 错误

  

解决方案

写HttpServletRequestWrapper把request保存下来,然后通过过滤器把保存下来的request再填充进去

1. 写一个CxmHttpServletRequestWrapper包装类,继承HttpServletRequestWrapper

@Component
public class CxmHttpServletRequestWrapper extends HttpServletRequestWrapper {

	private byte[] requestBody = new byte[0];
	private boolean bufferFilled = false;
	
	private ConcurrentHashMap<String, String> cxmHeaders = new ConcurrentHashMap<>();

	public CxmHttpServletRequestWrapper(HttpServletRequest request) {
		super(request);
	}

	@Override
	public ServletInputStream getInputStream() throws IOException {
		return new CachedServletInputStream(getRequestBody());
	}
	
	@Override
    public String getHeader(String name) {
		String headerValue = cxmHeaders.get(name);
		if (headerValue != null) {
			return headerValue;
		} else {
			return super.getHeader(name);
		}
    }
	
	public void setHeader(String name, String value){
        this.cxmHeaders.put(name, value);
    }

	public byte[] getRequestBody() throws IOException {
		if (bufferFilled) {
			return Arrays.copyOf(requestBody, requestBody.length);
		}
		InputStream inputStream = super.getInputStream();
		requestBody = IOUtils.toByteArray(inputStream);
		bufferFilled = true;
		return requestBody;
	}
}

写一个CachedServletInputStream继承ServletInputStream用来处理数据

public class CachedServletInputStream extends ServletInputStream {

	private ByteArrayInputStream buffer;

	public CachedServletInputStream(byte[] contents) {
		this.buffer = new ByteArrayInputStream(contents);
	}

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

	@Override
	public boolean isFinished() {
		return buffer.available() == 0;
	}

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

	@Override
	public void setReadListener(ReadListener listener) {
		throw new RuntimeException("Not implemented");
	}
}

2. 在过滤器中取值的时候转换成为我们自己的request包装类,并且把request传递下去

@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest requestWrapper = null;
		if (request instanceof HttpServletRequest) {
			requestWrapper = new CxmHttpServletRequestWrapper((HttpServletRequest) request);
		}

     chain.doFilter(requestWrapper, response);

}

3. 过滤器配置

@Slf4j
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

/**
	 * 
	 * @Title: Filters 
	 * @Description: 配置自定义的filter
	 * @return  
	 * @throws 
	 *
	 */
	@Bean
	public FilterRegistrationBean<CxmRequestValidFilter> Filters() {
	    FilterRegistrationBean<CxmRequestValidFilter> register = new FilterRegistrationBean<CxmRequestValidFilter>();
	    register.setFilter(new CxmRequestValidFilter());
	    register.addUrlPatterns("/*");
	    // 初始化filter的参数

	    register.addInitParameter("profile", profile);
	
	  	 register.setName("cxmRequestValidFilter");
	    return register;
	}


}

当在拦截器中需要对POST请求的参数进行处理时,有时会出现"Required request body is missing"异常。这是因为POST请求中的参数以流的形式存在,流数据只能读取一次。为了解决这个问题,可以使用HttpServletRequestWrapper来包装HttpServletRequest,这样可以将流保存起来,使参数能够多次读取。通过实现一个自定义的HttpServletRequestWrapper类,我们可以在拦截器中对请求参数进行处理,避免出现参数丢失的异常。 下面是一个示例拦截器的代码: ```java @Order(1) @WebFilter(filterName="koalaSignFilter",urlPatterns="/*") public class KoalaSignFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { // do nothing } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper=null; if(request instanceof HttpServletRequest) { requestWrapper=new KoalaHttpRequestWrapper((HttpServletRequest)request); } if(requestWrapper==null) { chain.doFilter(request, response); }else { chain.doFilter(requestWrapper, response); } } @Override public void destroy() { // do nothing } } ``` 在这个示例中,我们通过KoalaHttpRequestWrapper类来包装HttpServletRequest,并将包装后的request对象传递给FilterChain进行处理。这样就能够解决"Required request body is missing"异常问题。 总结来说,解决"Required request body is missing"拦截器的方法是通过使用HttpServletRequestWrapper包装HttpServletRequest,使得参数流能够多次读取。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [springboot-拦截器-过滤器-Required request body is missing 异常](https://blog.csdn.net/qq_33517683/article/details/78593487)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值