关于程序员:post请求体内容无法重复获取

119次阅读

共计 2035 个字符,预计需要花费 6 分钟才能阅读完成。

post 申请体内容无奈反复获取

为什么会无奈反复读取呢?

以 tomcat 为例,在进行申请体读取时理论底层调用的是 org.apache.catalina.connector.Request 的 getInputStream() 办法,而该办法返回的是 CoyoteInputStream 输出流

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 进行读取时

public int read(byte[] b, int off, int len) throws IOException {
  // 如果流敞开,则抛出异样
    if (closed) {throw new IOException(sm.getString("inputBuffer.streamClosed"));
    }
// 如果曾经读完了,则返回 -1
    if (checkByteBufferEof()) {return -1;}
    int n = Math.min(len, bb.remaining());
    bb.get(b, off, n);
    return n;
}

而流读取结束都会进行 close,这个流 close 之后,close 状态就置为了 true,所以导致流无奈进行二次读取

<!– more –>

那么如何解决呢?将 tomcat 的 Request 类进行从新实现吗?代价太大了,sun 公司当初在设计的时候就曾经提供了解决办法,对于申请和响应,sun 公司提供了包装类,能够 HttpServletRequestWrapper 类包装原始的 request 对象,实现了 HttpServletRequest 接口的所有办法,外部调用了所包装的 request 对象的对应办法;相应的也有 HttpServletResponseWrapper 类来包装原始的 response 对象继承 HttpServletRequestWrapper 来进行办法重写,能够应用 HttpServletResponseWrapper 和 HttpServletRequestWrapper 来进行定制响应和申请

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) {}};
    }
}

https://zhhll.icu/2020/javaweb/ 问题 /6.post 申请体内容无奈反复获取 /

本文由 mdnice 多平台公布

正文完
 0