有时候,我们需要用拦截器对Request或者Response流里面的数据进行拦截,读取里面的一些信息,也许是作为日志检索,也许是做一些校验,但是当我们读取里请求或者回调的流数据后,会发现这些流数据在下游就无法再次被消费了,这里面是其实存在着两个潜在的坑。
坑一
Request的 getInputStream()、getReader()、getParameter()方法互斥,也就是使用了其中一个,再使用另外的两,是获取不到数据的。除了互斥外,getInputStream()和getReader()都只能使用一次,getParameter单线程上可重复使用。
三个方法互斥原因
org.apache.catalina.connector.Request方法实现了javax.servlet.http.HttpServletRequest接口,我们来看看这三个方法的实现:
getInputStream
@Override
public ServletInputStream getInputStream() throws IOException {
if (usingReader) {
throw new IllegalStateException
(sm.getString("coyoteRequest.getInputStream.ise"));
}
usingInputStream = true;
if (inputStream == null) {
inputStream = new CoyoteInputStream(inputBuffer);
}
return inputStream;
}
getReader
@Override
public BufferedReader getReader() throws IOException {
if (usingInputStream) {
throw new IllegalStateException
(sm.getString("coyoteRequest.getReader.ise"));
}
usingReader = true;
inputBuffer.checkConverter();
if (reader == null) {
reader = new CoyoteReader(inputBuffer);
}
return reader;
}
首先来看getInputStream()和getReader()这两个方法,可以看到,在读流时分别用usingReader和usingInputStream标志做了限制,这两个方法的互斥很好理解。下面看一看getParameter()方法是怎么跟他们互斥的。
getParameter
@Override
public String getParameter(String name) {
// 只会解析一遍Parameter
if (!parametersParsed) {
parseParameters();
}
// 从coyoteRequest中获取参数
return coyoteRequest.getParameters().getParameter(name);
}
粗略一看好像没有互斥,别着急,继续往下看,我们进到parseParameters()方法中来看一看(可以直接看源码中间部分):
protected void parseParameters() {
//标识位,标志已经被解析过。
parametersParsed = true;
Parameters parameters = coyoteRequest.getParameters();
boolean success = false;
try {
// Set this every time in case limit has been changed via JMX
parameters.setLimit(getConnector().getMaxParameterCount());
// getCharacterEncoding() may have been overridden to search for
// hidden form field containing request encoding
String enc = getCharacterEncoding();
boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
if (enc != null) {
parameters.setEncoding(enc);
if (useBodyEncodingForURI) {
parameters.setQueryStringEncoding(enc);
}
} else {
parameters.setEncoding
(org.apache.co