【发布时间】: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 上进行了测试。
【问题讨论】:
标签: java http servlets post tomcat6