0

我对 Jakarta Commons HttpClient 有疑问。在我自己编写的 HttpServer 得到真正的请求之前,有一个请求是完全空的。这是第一个问题。 第一个问题解决了。这是由不必要的 URLConnection 引起的! 第二个问题是,有时请求数据在http请求的第三或第四行之后结束:

POST / HTTP/1.1
User-Agent: Jakarta Commons-HttpClient/3.1
Host: 127.0.0.1:4232

对于调试,我使用的是 Axis TCPMonitor。那里一切都很好,但空请求。

我如何处理流:

StringBuffer requestBuffer = new StringBuffer();

InputStreamReader is = new InputStreamReader(socket.getInputStream(), "UTF-8");

int byteIn = -1;
do {
    byteIn = is.read();
    if (byteIn > 0) {
        requestBuffer.append((char) byteIn);
    }
} while (byteIn != -1 && is.ready());

String requestData = requestBuffer.toString();

找到了一种处理流的新方法。我读取了所有标题参数并使用“内容长度”来读取帖子数据。

InputStream is = mySocket.getInputStream();
if (is == null) {
    return;
}
BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"));

// Read the request line
// ...
// ...

// Parse the header
Properties header = new Properties();
if (st.hasMoreTokens()) {
    String line = in.readLine();
    while (line != null && line.trim().length() > 0) {
        int p = line.indexOf(':');
        header.put(line.substring(0, p).trim().toLowerCase(), line.substring(p + 1).trim());
        line = in.readLine();
    }
}

// If the method is POST, there may be parameters
// in data section, too, read it:
String postLine = "";
if (method.equalsIgnoreCase("POST")) {
    long size = 0x7FFFFFFFFFFFFFFFl;
    String contentLength = header.getProperty("content-length");
    if (contentLength != null) {
        try {
            size = Integer.parseInt(contentLength);
        } catch (NumberFormatException ex) {
        }
    }
    postLine = "";
    char buf[] = new char[512];
    int read = in.read(buf);
    while (read >= 0 && size > 0 && !postLine.endsWith("\r\n")) {
        size -= read;
        postLine += String.valueOf(buf, 0, read);
        if (size > 0) {
            read = in.read(buf);
        }
    }
    postLine = postLine.trim();
    decodeParms(postLine, parms);
}

我如何发送请求:

client.getParams().setSoTimeout(30000);

method = new PostMethod(url.getPath());
method.getParams().setContentCharset("utf-8");
method.setRequestHeader("Content-Type", "application/xml; charset=utf-8");
method.addRequestHeader("Connection", "close");
method.setFollowRedirects(false);

byte[] requestXml = getRequestXml();

method.setRequestEntity(new InputStreamRequestEntity(new ByteArrayInputStream(requestXml)));

client.executeMethod(method);

int statusCode = method.getStatusCode();

有没有人知道如何解决这些问题?

亚历克斯

4

2 回答 2

1

我不知道第一个问题,但我认为你的第二个问题是由于这个:

} while (byteIn != -1 && is.ready());

如果发送方发送数据的速度不够快,接收方可能会is.ready()在发送下一个数据包之前调用。这将导致is.ready()返回false,这将导致循环停止。

最小的修复是将该行更改为:

} while (byteIn != -1);

编辑

但实际上,您需要按照@simonlord 的答案重写该方法。一次读取一个字节的无缓冲流是一个非常糟糕的主意。您最终会为每个read调用进行一次系统调用,这是非常低效的。

编辑 2

删除is.ready()导致延迟的原因是您没有适当注意 HTTP 协议。问题是 HttpClient 代码保持 TCP 连接的请求端打开以允许重用连接。简单(但次优)的解决方案是配置 HttpClient 以关闭连接的请求端。您的代码会立即看到 EOF。您实际上所做的是另一种解决方案。

坦率地说,除非您准备好深入了解整个 HTTP 规范并忠实地实现它,否则您甚至不应该尝试实现服务器端 HTTP 协议。现有的实现可能会比你可以拼凑的任何东西更快、更可靠。实现规范子集的问题在于,您的服务器可能需要与真正的浏览器通信,该浏览器使用您没有费心实施/测试的部分规范。

于 2010-03-08T12:31:56.657 回答
1

这可能与您的 while 循环中的第二个条件有关,isReady() 方法可能会在下一次读取可能阻塞时返回 false - 但您并不真正关心它是否阻塞,因此我们可以简单地删除它(您可以在这里阅读更多内容:http: //java.sun.com/j2se/1.5.0/docs/api/java/io/InputStreamReader.html#ready%28%29)。尝试更改为:

byte[] buf = new byte[500];
while((is.read(buf))>-1){
  requestBuffer.append(new String(buf).trim());
  buf = new byte[500];
}

现在你应该得到整个请求。

于 2010-03-08T12:33:04.767 回答