servlet 中读取请求正文的问题
Posted
技术标签:
【中文标题】servlet 中读取请求正文的问题【英文标题】:Problem reading request body in servlet 【发布时间】:2011-03-26 06:15:12 【问题描述】:我正在编写作为测试/验证一部分的 HTTP 代理 系统。代理过滤来自客户端设备的所有请求 并将它们引导到各种被测系统。
代理被实现为一个 servlet,每个请求都在其中被转发 到目标系统,它同时处理 GET 和 POST。有时 目标系统的响应被改变以适应各种测试 条件,但这不是问题的一部分。
转发请求时,所有标头都被复制,除了那些 这是实际 HTTP 传输的一部分,例如 Content-Length 和 连接头。
如果请求是 HTTP POST,那么请求的实体主体是 也转发,这里有时不起作用。
从servlet请求中读取实体主体的代码如下:
URL url = new URL(targetURL);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
String method = request.getMethod();
java.util.Enumeration headers = request.getHeaderNames();
while(headers.hasMoreElements())
String headerName = (String)headers.nextElement();
String headerValue = request.getHeader(headerName);
if (...) // do various adaptive stuff based on header
conn.setRequestProperty(headerName, headerValue);
//这里是失败的部分
char postBody[] = new char[1024];
int len;
if(method.equals("POST"))
logger.debug("guiProxy, handle post, read request body");
conn.setDoOutput(true);
BufferedReader br = request.getReader();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
do
logger.debug("Read request into buffer of size: " + postBody.length);
len = br.read(postBody, 0, postBody.length);
logger.debug("guiProxy, send request body, got " + len + " bytes from request");
if(len != -1)
bw.write(postBody, 0, len);
while(len != -1);
bw.close();
所以发生的事情是第一次收到 POST,-1 从请求阅读器读取字符,wireshark 跟踪显示 包含 URL 编码的 post 参数的实体主体存在 它在一个 TCP 段中,因此没有网络相关 差异。
第二次,br.read成功返回了232字节 POST 请求实体正文和每个即将到来的请求也可以正常工作。
第一个和即将到来的 POST 请求之间的唯一区别是 在第一个中,没有 cookie,但在第二个中, 存在一个映射到 JSESSION 的 cookie。
这可能是实体主体不可用的副作用,因为 servlet 容器中的请求处理已经读取 POST 参数,但为什么它对即将到来的请求起作用。
我相信解决方案当然是忽略实体主体 包含 URL 编码数据的 POST 请求并获取所有参数 从 servlet 请求而不是使用 getParameter 并重新插入它们 int 传出请求。
尽管这很棘手,因为 POST 请求可能包含 GET 参数,现在不在我们的应用程序中,而是在实现它 正确的是一些工作。
所以我的问题基本上是:为什么读者从 request.getReader() 读取时返回 -1 并且实体主体是 出现在请求中,如果实体主体不可用于 读取,那么 getReader 应该抛出一个非法状态异常。一世 也尝试过使用 getInputStream() 与 InputStream 相同 结果。
所有这些都在 apache-tomcat-6.0.18 上进行了测试。
【问题讨论】:
【参考方案1】:所以我的问题基本上是:为什么 request.getReader() 的阅读器在阅读时返回 -1。
当没有正文或已已经被读取时,它将返回 -1。你不能读两遍。确保请求/响应链中之前没有任何内容读取过它。
并且请求中存在实体主体,如果实体主体不可读取,则 getReader 应抛出非法状态异常。
它只会在你之前已经在请求上调用过getInputStream()
时抛出,而不是在它不可用时抛出。
我也尝试过使用 getInputStream() 的 InputStream,结果相同。
毕竟,我更喜欢流式传输字节而不是字符,因为这样你就不需要考虑字符编码(你现在还没有这样做,当你得到这一切时,这可能会导致未来的问题工作)。
【讨论】:
似乎 cookie 的存在阻止了 servlet 容器读取 POST 正文。这就解释了为什么以下发布请求有效,因为设置 cookie 后它就有效。现在对我来说有点尴尬的解决方案是手动将所有 POST 参数传输到代理的请求实体主体,但它现在可以工作。我相信构建代理的正确方法是使用 servlet 过滤器,然后可以控制整个请求。【参考方案2】:似乎,那动人
BufferedReader br = request.getReader()
在所有操作之前,读取请求(如 request.getHeader() )对我来说效果很好。
【讨论】:
以上是关于servlet 中读取请求正文的问题的主要内容,如果未能解决你的问题,请参考以下文章
如何使用保留请求正文和响应正文的 servlet 过滤器记录请求和响应?
当一个请求由一个 servlet 处理时,是整个请求头/正文/等。已经加载了吗?