post请求体内容无法重复获取
为什么会无法重复读取呢?
以tomcat为例,在进行请求体读取时实际底层调用的是org.apache.catalina.connector.Request的getInputStream()方法,而该方法返回的是CoyoteInputStream输入流
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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;
}
|
在使用CoyoteInputStream进行读取时
1 2 3 4 5 6 7 8 9 10 11 12 13
| public int read(byte[] b, int off, int len) throws IOException { if (closed) { throw new IOException(sm.getString("inputBuffer.streamClosed")); }
if (checkByteBufferEof()) { return -1; } int n = Math.min(len, bb.remaining()); bb.get(b, off, n); return n; }
|
而流读取完毕都会进行close,这个流close之后,close状态就置为了true,所以导致流无法进行二次读取
那么如何解决呢?将tomcat的Request类进行重新实现吗?代价太大了,sun公司当初在设计的时候就已经提供了解决方法,对于请求和响应,sun公司提供了包装类,可以HttpServletRequestWrapper类包装原始的request对象,实现了HttpServletRequest接口的所有方法,内部调用了所包装的request对象的对应方法;相应的也有HttpServletResponseWrapper类来包装原始的response对象继承HttpServletRequestWrapper来进行方法重写,可以使用HttpServletResponseWrapper和HttpServletRequestWrapper来进行定制响应和请求
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
| public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private byte[] body;
private HttpServletRequest orgRequest;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); this.orgRequest = request; body = HttpHelper.getBody(request); }
public HttpServletRequest getOrgRequest() { return this.orgRequest; }
@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) {
} }; } }
|