问题现场:
原因:
HttpServletRequest 的 getInputStream() 和 getReader() 都只能读取一次。
因为 我们使用@RequestBody 注解,读取body参数;而 又 写了拦截器,也需要将post请求,body数据拿出来。
由于@RequestBody 也是流的形式读取,流读了一次就没有了。
解决方案:
过滤器是优先于拦截器的, 我们写一个过滤器,在过滤器里面 把流数据 copy一份出来用,也就是复写一哈。
在拦截器上使用我们复写的流数据就行。
BodyWrapperFilter.java
import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; /** * @Author: JCccc * @Date: 2022-6-12 10:35 * @Description: */ public class BodyWrapperFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { ServletRequest requestWrapper = null; if(servletRequest instanceof HttpServletRequest) { requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest); } if(requestWrapper == null) { filterChain.doFilter(servletRequest, servletResponse); } else { filterChain.doFilter(requestWrapper, servletResponse); } } }
CustomHttpServletRequestWrapper.java
import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; import java.nio.charset.StandardCharsets; /** * @Author: JCccc * @Date: 2022-6-12 10:36 * @Description: 重写一个自己的 RequestWrapper 拿出body给自己用 */ public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper { private byte[] body; public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); BufferedReader reader = request.getReader(); try (StringWriter writer = new StringWriter()) { int read; char[] buf = new char[1024 * 8]; while ((read = reader.read(buf)) != -1) { writer.write(buf, 0, read); } this.body = writer.getBuffer().toString().getBytes(); } } public String getBody(){ return new String(body, StandardCharsets.UTF_8); } @Override public ServletInputStream getInputStream() { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() { return byteArrayInputStream.read(); } }; } @Override public BufferedReader getReader() { return new BufferedReader(new InputStreamReader(this.getInputStream())); } }
WebApplicationConfig.java
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Author: JCccc * @Date: 2022-6-23 10:52 * @Description: */ @Configuration public class WebApplicationConfig { @Bean BodyWrapperFilter getBodyWrapperFilter(){ return new BodyWrapperFilter(); } @Bean("bodyWrapperFilter") public FilterRegistrationBean<BodyWrapperFilter> checkUserFilter(BodyWrapperFilter bodyWrapperFilter) { FilterRegistrationBean<BodyWrapperFilter> registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(bodyWrapperFilter); registrationBean.addUrlPatterns("/*"); registrationBean.setOrder(1); registrationBean.setAsyncSupported(true); return registrationBean; } }
然后就是在拦截器里面,如果我们想取出body,我们改成这样用:
CustomHttpServletRequestWrapper wrapper = (CustomHttpServletRequestWrapper) request;
String nowParams = wrapper.getBody();
效果:
好的,这篇就到这。