interceptor or controller 获取流异常
最近做一个拦截器获取参数的需求 (还有一个在 controller 获取 request 的流的时候也出现了同样的问题。),本来运行的好好的,可是迭代了几个版本之后,发现所有获取流的方法都出现了问题。经过排查发现是加了几个拦截器。而 request.getInputStream() 只可以读一次。所以导致后续从request获取数据全部是空,才出现的异常。所以我们可以通过 filter 将request存起来,这样用的时候就不会出异常了。
1. 工具类
import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; public class HttpHelper { 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(); } }
2. 包装类处理流
import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; public class RequestReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public RequestReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8")); } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } }
3. 添加过滤器
import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; public class HttpServletRequestReplacedFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper = null; if(request instanceof HttpServletRequest) { requestWrapper = new RequestReaderHttpServletRequestWrapper((HttpServletRequest) request); } //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。 // 在chain.doFiler方法中传递新的request对象 if(requestWrapper == null) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); } } @Override public void init(FilterConfig arg0) throws ServletException { } }
4. 注册过滤器
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RpcAuthenticationConfiguration { @Bean public FilterRegistrationBean httpServletRequestReplacedRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new HttpServletRequestReplacedFilter()); registration.addUrlPatterns("/*"); registration.setName("httpServletRequestReplacedFilter"); registration.setOrder(1); return registration; } }
。