构建可重复读取inputStream的request
我们知道,request的inputStream只能被读取一次,多次读取将报错,那么如何才能重复读取呢?答案之一是:增加缓冲,记录已读取的内容。
代码如下所示:
import lombok.extern.log4j.Log4j2;
import org.springframework.mock.web.DelegatingServletInputStream;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
/**
* request wrapper: 可重复读取request.getInputStream
*/
@Log4j2
public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper {
private static final int BUFFER_START_POSITION = 0;
private static final int CHAR_BUFFER_LENGTH = 1024;
/**
* input stream 的buffer
*/
private final String body;
/**
* @param request {@link javax.servlet.http.HttpServletRequest} object.
*/
public RepeatedlyReadRequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
InputStream inputStream = null;
try {
inputStream = request.getInputStream();
} catch (IOException e) {
log.error("Error reading the request body…", e);
}
if (inputStream != null) {
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
char[] charBuffer = new char[CHAR_BUFFER_LENGTH];
int bytesRead;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, BUFFER_START_POSITION, bytesRead);
}
} catch (IOException e) {
log.error("Fail to read input stream",e);
}
} else {
stringBuilder.append("");
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
return new DelegatingServletInputStream(byteArrayInputStream);
}
}
接下来,需要一个对应的Filter.
代码如下所示:
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class RepeatlyReadFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//Do nothing
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
request = new RepeatedlyReadRequestWrapper((HttpServletRequest) request);
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
//Do nothing
}
}
最后,需要在web.xml中,增加该Filter的配置(略)。