我正在用Java编写一个简单的代理。我无法将整个给定请求读入字节数组。具体来说,在下面的循环中,即使客户端已经发送了它将要发送的所有数据(即,永远不会到达流的末尾),对“读取”的调用也会阻塞。由于我无法确定是否是时候开始写输出,直到我读完整个输入,这会造成一些麻烦。如果我终止与服务器的连接,最终会到达流的末尾,一切都顺利完成(来自客户端的所有数据,在这种情况下,Firefox请求www.google.com,已被服务器读取) ,并且它能够根据需要处理它,但显然它不能将任何东西发送回客户端。)
public static void copyStream(InputStream is, OutputStream os) throws IOException
{
int read = 0;
byte[] buffer = new byte[BUFFER_SIZE];
while((read = is.read(buffer, 0, BUFFER_SIZE)) != -1)
{
os.write(buffer, 0, read);
}
return;
}
InputStream直接来自客户端套接字(getInputStream(),然后缓冲); OutputStream是ByteArrayOutputStream。
我做错了什么?
答案 0 :(得分:4)
通常在HTTP中,Content-Length
标头表示您应该从流中读取多少数据。基本上它会告诉你双重换行符后面有多少字节(实际上是双 - \r\n
),表示HTTP标头的结束。有关详细信息,请参阅W3C
如果没有发送Content-Length
标头,您可以尝试在经过一定时间后中断读取而没有通过连接发送数据,尽管这绝对不是优选的。
(我假设您将以某种方式处理您正在阅读的数据,否则您可以在阅读时写出每个字节)
答案 1 :(得分:1)
所有现代浏览器都支持HTTP 1.1,它具有一个名为“keep-alive”或“persistent connections”的功能,默认情况下允许客户端为服务器重用HTTP 1.1连接以获取多个请求(请参阅{ {3}})。 因此,如果您将FF指向http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html,则与www.google.com:80的连接将保持打开一段时间,即使第一个请求已完成。因此,在您的应用程序没有对HTTP协议的基本了解的情况下,您无法知道是否已发送所有数据。 您可以通过在连接上使用超时来以某种方式避免这种情况,希望客户端不会卡在某处,并且该静默实际上意味着数据块的结束。 另一种方法是重写服务器响应头,将您的代理通告为HTTP 1.0兼容,而不是1.1,从而禁止客户端使用持久连接。
答案 2 :(得分:1)
请注意,并非所有连接都有Content-Length
标头;有些人可能正在使用Transfer-Encoding: chunked
,其中内容长度被编码并作为正文的一部分包含在内。