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