I don't know if you check the user's allergy. If you don't check, the user belongs to some attack scripts, then our service will be forced! So we first need to read the user's data through the filter for safety verification, which involves an action, that is, we need to read the user's data in the filter for verification, and then release it after passing.
problem
If our data is a get request, it's OK, but if it's a large amount of data, we need to pass the data through post json, which is actually a stream. If we read out the parameters in the filter, and then release them. When we get to the Servlet, @ RequestBody can't get the data, because post json uses stream passing. After the stream is read, it doesn't exist. So we read it in the filter ,@ReqeustBody Naturally, I can't read the data. At the same time, I will report the following error.
- Read the data in the body in the filter
@WebFilter @Slf4j public class CheckUserFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; // Read data in filter BufferedReader reader = request.getReader(); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } reader.close(); System.out.println(sb.toString()); filterChain.doFilter(request, res); } }
- There is an exception, that is, the content has been read and you cannot call
{ "id":"1", "username":"bingfeng"} java.lang.IllegalStateException: UT010003: Cannot call getInputStream(), getReader() already called at io.undertow.servlet.spec.HttpServletRequestImpl.getInputStream(HttpServletRequestImpl.java:666) at javax.servlet.ServletRequestWrapper.getInputStream(ServletRequestWrapper.java:152) at javax.servlet.ServletRequestWrapper.getInputStream(ServletRequestWrapper.java:152)
solve
- HttpServletRequestWrapper
So what should we do if there is such a problem? Can we save the data through an intermediate variable, and then we can read it all the time, which will solve the problem? Where is it kept? At this time, HttpServletRequestWrapper will come into use.
In fact, you can understand it as a Request wrapper class. There are some methods in Reqeust. We can inherit this class, rewrite the methods in this class, save the parameters in the body in a byte array, and pass the wrapper class in when we release it. Can't we get the parameters all the time?
- Encapsulate Request class
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; /** * Set of all parameters */ private Map<String, String[]> parameterMap; public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); BufferedReader reader = request.getReader(); body = readBytes(reader); parameterMap = request.getParameterMap(); } @Override public BufferedReader getReader() throws IOException { ServletInputStream inputStream = getInputStream(); if (null == inputStream) { return null; } return new BufferedReader(new InputStreamReader(inputStream)); } @Override public Enumeration<String> getParameterNames() { Vector<String> vector = new Vector<>(parameterMap.keySet()); return vector.elements(); } @Override public ServletInputStream getInputStream() throws IOException { if (body == null) { return null; } final ByteArrayInputStream bais = new ByteArrayInputStream(body); 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 bais.read(); } }; } /** * Convert to byte array with BufferedReader and character encoding set * * @param br * @return * @throws IOException */ private byte[] readBytes(BufferedReader br) throws IOException { String str; StringBuilder retStr = new StringBuilder(); while ((str = br.readLine()) != null) { retStr.append(str); } if (StringUtils.isNotBlank(retStr.toString())) { return retStr.toString().getBytes(StandardCharsets.UTF_8); } return null; } }
- Transform the filter
@WebFilter @Slf4j public class CheckUserFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper(request); // Read data from Request's wrapper class BufferedReader reader = requestWrapper.getReader(); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } reader.close(); System.out.println(sb.toString()); filterChain.doFilter(requestWrapper, res); } }
After this configuration, even if we get the parameters in the filter, the request will arrive at the Servlet.
If the basic knowledge IO is not very solid, the first thing I see is that this problem is really muddled. I also solved it after Baidu. It's really worth recording. Sometimes we will save and output all the requested parameters. If it's post json data at this time, if it's not particularly clear, this problem may also occur.
<p style="text- align:center;font-weight :bold;color:#0e88eb;font- size:20px "> if you are a member of the sun arch, you will not be able to donate</p>
<p style="text- align:center;font-weight :bold;color:#773098;font- size:16px "> please pay attention to more</p>