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(); } }