Ern*_*lli 2 java post servlets http tomcat6
我正在编写一个HTTP代理,它是测试/验证系统的一部分.代理过滤来自客户端设备的所有请求,并将它们引导到各种受测试的系统.
代理实现为servlet,每个请求都转发到目标系统,它处理GET和POST.有时,目标系统的响应会被改变以适应各种测试条件,但这不是问题的一部分.
转发请求时,将复制所有标头,但实际HTTP传输的标头除外,例如Content-Length和Connection标头.
如果请求是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);
}
Run Code Online (Sandbox Code Playgroud)
//这里是失败的部分
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();
}
Run Code Online (Sandbox Code Playgroud)
所以发生的事情是,第一次收到POST时,从请求读取器读取-1个字符,wireshark跟踪显示包含URL编码的post参数的实体主体在那里并且它在一个TCP段中,因此没有网络相关差异.
第二次,br.read成功返回POST请求实体主体中的232个字节,并且每个即将发出的请求也都有效.
第一个和即将发布的POST请求之间的唯一区别是,在第一个请求中,不存在cookie,但在第二个中,存在映射到JSESSION的cookie.
由于servlet容器中的请求处理已经读取了POST参数,因此它可能是实体主体不可用的副作用,但为什么它适用于即将到来的请求.
我认为解决方案当然是忽略包含URL编码数据的POST请求的实体主体,并使用getParameter从servlet请求中获取所有参数,并将它们重新插入传出请求中.
尽管这很棘手,因为POST请求可能包含GET参数,而不是现在我们的应用程序,但正确实现它是一些工作.
所以我的问题基本上是:为什么来自request.getReader()的阅读器在读取时返回-1并且请求中存在实体主体,如果实体主体不可用于读取,则getReader应该抛出非法状态异常.我也尝试使用具有相同结果的getInputStream()与InputStream.
所有这些都在apache-tomcat-6.0.18上进行了测试.
所以我的问题基本上是:为什么request.getReader()的阅读器在阅读时返回-1.
当没有身体或已经被读取时,它将返回-1 .你不能读两遍.确保请求/响应链中的任何内容都没有读过它.
并且请求中存在实体主体,如果实体主体不可读,则getReader应该抛出非法状态异常.
它只会在您之前已经调用getInputStream()过请求时抛出,而不是在它不可用时抛出.
我也尝试使用具有相同结果的getInputStream()与InputStream.
毕竟,我更喜欢流式传输字节而不是字符,因为您不需要考虑字符编码(现在你没有做到这一点,这可能会导致将来出现问题) .
| 归档时间: |
|
| 查看次数: |
9062 次 |
| 最近记录: |