SpringBoot的使用HandlerInterceptor 經過request.getInputStream()獲取數據報Stream closed異常分析解決。
攔截器:java
@Component public class AmsInterceptor implements HandlerInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(AmsInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HandlerMethod method = (HandlerMethod) handler; String cn = method.getBean().getClass().getName(); String mn = method.getMethod().getName(); String bodyString = getBodyString(request); LOGGER.info("preHandle : [{}]#[{}]#[{}]", cn, mn, bodyString); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { LOGGER.info("postHandle : [{}]", request.getRequestURI()); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { LOGGER.info("afterCompletion : [{}]", request.getRequestURI()); } } public static String getBodyString(HttpServletRequest request) throws IOException { StringBuilder sb = new StringBuilder(); InputStream inputStream = null; BufferedReader reader = null; try { inputStream = request.getInputStream(); reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString(); }
方法:spring
/** * 獲取 Body 參數 * * @param request * @return * @throws IOException */public static Map<String, Object> getAllRequestParam(final HttpServletRequest request) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); String str = ""; StringBuilder wholeStr = new StringBuilder(); //一行一行的讀取body體裏面的內容; while ((str = reader.readLine()) != null) { wholeStr.append(str); } //轉化成json對象 return JSONObject.parseObject(wholeStr.toString(), Feature.OrderedField); }
String bodyString = getBodyString(request);
咱們在攔截器中經過request.getInputStream();
獲取到body中的信息後,以後在controller
中使用了@RequestBody
註解獲取參數報以下錯誤:json
java.io.IOException: UT010029: Stream is closed
Controller方法:app
@RequestMapping(value = {"/getOnlineService"}, method = {RequestMethod.POST}, produces = "application/json;charset=UTF-8") public ApiReply getOnlineServiceByBusinessId(@Validated @RequestBody BusinessCateQuery query) { logger.info("getOnlineServiceByBusinessId method param {}", query.toString()); ApiReply resp = new ApiReply(); try { List<CustServiceRep> serviceList = businessClassService.getOnlineServiceByBusinessId(query.getBusinessId(), query.getOrganId()); resp.setModel(serviceList); resp.setMessage("success"); } catch(Exception e) { logger.error("根據業務分類獲取在線客服接口錯誤:_" + e.getMessage(), e); return new ApiReply(ApiReplyCode.FAILED); } return resp; }
spring boot項目,RequestBody裏數據,只能經過流的方式獲取,而在aop裏獲取了,在Controller裏使用@RequestBody註解再獲取就報ide
I/O error while reading input message; nested exception is java.io.IOException: Stream closed
這個流只能用一次,用過以後,就不能再取數據了。post
由於咱們在AOP裏邊有獲取body的調用,因此,再controller中使用@RequestBody時就報錯了。ui
先讀取流,而後在將流寫進去,下次就能夠再讀取流了。spa
public class ReHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] bodyBuf; public ReHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); bodyBuf = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8")); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream stream = new ByteArrayInputStream(bodyBuf); 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() throws IOException { return stream.read(); } }; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } }
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; String uri = request.getRequestURI(); long start = System.currentTimeMillis(); LOGGER.info("請求地址 : [{}]", uri); ServletRequest requestWrapper; if (servletRequest instanceof HttpServletRequest) { requestWrapper = new ReHttpServletRequestWrapper((HttpServletRequest) servletRequest); if (requestWrapper != null) { servletRequest = requestWrapper; } } filterChain.doFilter(servletRequest, servletResponse); long end = System.currentTimeMillis(); LOGGER.info("請求地址 : [{}], 耗時 : [{}] ms", uri, (end - start)); }
這樣咱們就能夠在Interceptor
中經過request.getInputStream();
獲取到body
中的信息。code