OwlFocus

OncePerRequestFilter流只能读取一次

OncePerRequestFilter调用问题

在Spring自定义过滤器中,调用HttpServletRequest的getReader方法,为了获取post上传的参数,得到参数后继续调用doFilter出现以下错误。

错误信息

Request processing failed; nested exception is java.lang.IllegalStateException: getReader() has already been called for this request

解决

HttpServletRequest的getInputStream()和getReader() 都只能读取一次,由于RequestBody是流的形式读取,那么流读了一次就没有了,所以只能被调用一次。
先将RequestBody保存,然后通过Servlet自带的HttpServletRequestWrapper类覆盖getReader()和getInputStream()方法,
使流从保存的body读取。然后再Filter中将ServletRequest替换为AuthenticationRequestWrapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class AuthenticationRequestWrapper extends HttpServletRequestWrapper {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationRequestWrapper.class);
//post请求参数
private final String payload;
public AuthenticationRequestWrapper (HttpServletRequest request) throws AuthenticationException {
super(request);
// read the original payload into the payload variable
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
// read the payload into the StringBuilder
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
// make an empty string since there is no payload
stringBuilder.append("");
}
} catch (IOException ex) {
logger.error("Error reading the request payload", ex);
throw new AuthenticationException("Error reading the request payload", ex);
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException iox) {
// ignore
}
}
}
payload = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream () throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(payload.getBytes());
ServletInputStream inputStream = new ServletInputStream() {
public int read ()
throws IOException {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
return inputStream;
}
public String getPayload() {
return payload;
}
}

调用

1
2
3
4
5
6
7
private void checkToken(HttpServletRequest req, HttpServletResponse resp, FilterChain filterChain)
throws IOException, ServletException, AuthenticationException {
AuthenticationRequestWrapper request = new AuthenticationRequestWrapper((HttpServletRequest) req);
HttpServletResponse response = (HttpServletResponse) resp;
doFilter(request, response, filterChain);
}

Thx