如果 HTTP 协议没有 EOF 字符,为什么从 HttpURLConnection 循环的读取行 while 不会阻止?



我试图理解使用HttpURLConnection类(或HttpsURLConnection类)在Java中执行HTTP请求的逻辑。下面是我执行GET请求并将所有响应有效负载打印到标准输出的代码。

URL url = new URI("https://swapi.dev/api/planets/1/");
String line;
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/json");
BufferedReader input = new BufferedReader(
new InputStreamReader(connection.getInputStream())
);
// read all data from response payload & print to screen
while ((line=input.readLine()) != null) {
System.out.println(line);
}
System.out.println("All data retrieved!");

问题来了:这段代码工作得很好,成功地读取了所有信息并完成了运行!我的问题是,为什么执行最终不是在while循环的input.readLine()部分被阻塞?

当我在TCP级别上执行类似的while-loop读取时,这样的readLine将阻塞,直到从客户端关闭连接。根据HttpURLConnection类的文档(这里),底层TCP连接通常不会因为性能原因而关闭。因此,如果我想象connection.getInputStream()与TCP模拟中的socket.getInputStream()相同,我预计input.readLine()调用最终也会阻塞。

我猜这个方法可能会在HttpURLConnection的情况下被覆盖的某个地方(也许利用Content-Length头属性?)但是,我在任何地方都找不到这个覆盖。

由于我试图尽可能深入,如果您能帮助准确定位HttpURLConnection类如何导致我的while循环最终结束,那将是伟大的。

为什么在while循环的input.readLine()部分最终没有执行阻塞?

因为当Reader.readLine()调用到达它正在读取的输入流的流尾时,它将返回null

当服务器端发送完响应数据时,它将到达客户端的流结束…客户端已经全部读过了。

流的结尾可能与服务器关闭TCP/IP连接对应,也可能不对应。如果HTTP块传输编码用于HTTP连接,则不会。当客户端和服务器同意对多个请求/响应使用单个连接时,使用分块编码。块头将告诉客户端,当它已经到达一个文档的结尾…并且它应该在输入流上发出流结束信号。

content-length报头可能会也可能不会出现在1中。但是请记住,服务器可以在没有content-length头的情况下发送响应…这意味着客户端不会提前知道需要多少数据,并且无法将其用于"框架";响应体。

详细信息请参考指定HTTP的rfc。(这比查看客户端Java源代码要好。客户端代码只告诉了你故事的一半。)


1 - HTTP规范规定,如果服务器在响应头中包含content-length,它必须准确地发送该字节数。但是,如果服务器发送的字节比它说的少或多,它不会强制任何特定的客户端行为。

相关内容

  • 没有找到相关文章

最新更新