springboot在接收http请求的时候读取的request的inputStream,造成我们想自己读取inputStream的时候发现inputStream已经无法读取了。
为了读取inputStream,我们应该在springboot读取之前把inputStream的内容暂存先来。
1 这里要使用一个类HttpServletRequestWrapper,我们写一个类继承这个类,把传入的request中的inputStream转为byte[] 暂存下来,重写其中的getInputStream方法,每次返回由暂存的byte转换而来的 inputStream。
import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; import java.util.Collection; import java.util.stream.Collectors; import javax.servlet.ReadListener; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.Part; import org.springframework.web.bind.annotation.RequestMethod; public class InputStreamHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] streamBody; private static final int BUFFER_SIZE = 4096; public InputStreamHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); byte[] bytes = new byte[0]; String uri = request.getRequestURI(); if (Objects.isNull(request.getHeader("Content-Type")) || request.getHeader("Content-Type").contains("multipart/form-data;")) { bytes = inputStream2Byte(request.getInputStream()); } else if (isFormPost(request)) { // 从ParameterMap获取参数,并保存以便多次获取 bytes = params2Byte(request); } else { bytes = inputStream2Byte(request.getInputStream()); } streamBody = bytes; // this.setRequest(this); } private boolean isFormPost(HttpServletRequest request) { return RequestMethod.POST.name().equals(request.getMethod()); } private byte[] params2Byte(HttpServletRequest request) { byte[] bytes = request.getParameterMap().entrySet().stream().map(entry -> { String result; String[] value = entry.getValue(); if (value != null && value.length > 1) { result = Arrays.stream(value).map(s -> entry.getKey() + "=" + s).collect(Collectors.joining("&")); } else { result = entry.getKey() + "=" + value[0]; } return result; }).collect(Collectors.joining("&")).getBytes(); return bytes; } private byte[] inputStream2Byte(InputStream inputStream) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] bytes = new byte[BUFFER_SIZE]; int length; while ((length = inputStream.read(bytes, 0, BUFFER_SIZE)) != -1) { outputStream.write(bytes, 0, length); } return outputStream.toByteArray(); } @Override public ServletInputStream getInputStream() throws IOException { ByteArrayInputStream inputStream = new ByteArrayInputStream(streamBody); return new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener listener) { } @Override public int read() throws IOException { return inputStream.read(); } }; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } }
2.这里要使用一个神奇的filter:HiddenHttpMethodFilter
在这个类中调用之前定义的 InputStreamHttpServletRequestWrapper类,并把实例化之后的类传入以后的filter中,这样以后所有的 ServletRequest 都是我们自己定义的了。
import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.filter.HiddenHttpMethodFilter; import org.springframework.web.filter.OncePerRequestFilter; import com.esri.rest.configure.helper.InputStreamHttpServletRequestWrapper; public class InputStreamWrapperFilter extends HiddenHttpMethodFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ServletRequest servletRequest = new InputStreamHttpServletRequestWrapper(request); filterChain.doFilter(servletRequest, response); } }
3,最后一步:把filter加入springboot 配置
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.web.filter.HiddenHttpMethodFilter; import com.esri.rest.filter.InputStreamWrapperFilter; @Configuration public class RequestConfig { @Bean @Order(1) public HiddenHttpMethodFilter hiddenHttpMethodFilter() { return new InputStreamWrapperFilter(); } }