【问题标题】:BufferedReader stuck in readLine() [closed]BufferedReader 卡在 readLine() [关闭]
【发布时间】:2021-01-26 07:58:57
【问题描述】:

我正在尝试从 Google Chrome 获取 HTTP 请求以获取其数据。为此,我使用来自BufferedReaderreadLine(),但由于某种原因,我认为它卡在最后一行,因为缓冲区保持打开状态并且它一直在等待更多输入。这是我在 while 循环中使用的代码:

String line;
ArrayList<String> request = new ArrayList<String>();
while ((line = inFromClient.readLine()) != null) {
    request.add(line);
}

如果我强行打破循环它可以工作,基本上我试图有效地读取所有行,但没有ready()的不一致

【问题讨论】:

  • 卡在最后一行是什么意思?它卡在}
  • 我不知道谷歌浏览器如何将其数据发送到您的程序,但我认为它可能会使流保持打开状态并将其重用于所有 http 请求。如果我查看BufferedReader#readLine() 的文档,它会说“如果已到达流的末尾,则 [returns] null”。我怀疑您的循环并没有真正“卡住”,它只是在等待更多数据。仅仅因为您读取了所有可用数据并不意味着您已到达数据流的末尾。
  • 这可能会有所帮助:stackoverflow.com/questions/5987970/…
  • 你可以检查BufferedReader#ready()而不是空检查。
  • @HamzaBelmellouki - 建议使用ready() 作为解决方案......这是个坏主意。

标签: java bufferedreader


【解决方案1】:

HTTP 看起来像一个疯狂的简单协议,但事实并非如此;您应该使用 HTTP 客户端库,例如内置的 java.net.http 客户端。

问题在于“给我我的数据,然后关闭它”的概念是 HTTP/1.0,而且已经过时了几十年。 HTTP/2.0 和 HTTP/3.0 是二进制协议,HTTP/1.1 倾向于保持连接打开。一般来说,“读取行”,甚至“使用阅读器”(如读取字符而不是字节)是错误的做法,因为 HTTP 不是文本协议。我知道。它看起来像一个。不是。

这里是一个高度过度简化的概述,例如浏览器读取 HTTP/1.1 响应:

  1. 使用原始字节处理,因为 HTTP 正文内容是原始的(或可以是原始的),因此将整个内容包装到例如InputStreamReaderBufferedReader 不适合。
  2. 继续读取,直到读取了 0x0A 字节(ASCII 中的换行符)、 X 字节,并且您的缓冲区已满,其中 X 不是特别大。不希望出现行为不良的服务器或在您连接到不同(非 HTTP)服务时出现误解而导致内存问题!将第一行解析为 HTTP/1.1 响应。
  3. 继续执行此循环以获取所有标题。使用相同的“我的缓冲区有限制”技巧来避免内存问题。
  4. 然后检查响应代码以确定是否会有正文。它是 HTTP/1.1,所以你不能只是说:“好吧,如果连接关闭,我想没有人来了”。是否会来主要取决于响应代码。
  5. 假设存在正文,请读取将标题与正文分开的双换行符。
  6. 如果内容是作为分块编码(常见)传输的,则开始将数据块传输到缓冲区中,但请检查您是否读取了整个块。读取分块编码本身就是一种游戏,真的。
  7. 或者,HTTP/1.1 要求如果不使用分块编码,则存在 Content-Length。使用此标头可准确了解要读取的字节数。
  8. “换行符”和“关闭连接”都不能作为 HTTP/1.1 中“数据结束”的有意义的标记,所以不要这样做。
  9. 然后将内容+标头+返回码逐字传递给请求代码,或者稍微修饰一下。例如,如果 Content-Type 标头存在且值为 text/html; encoding=UTF-8,您可以考虑获取正文数据并通过 UTF-8 (new String(byteArray, StandardCharsets.UTF_8);) 将其转换为字符串。

请注意,我已经忽略了服务器所做的一些奇怪行为,因为在过去,一些愚蠢的浏览器做了奇怪的事情,现在是现状(例如,范围请求非常奇怪),当然还有 HTTP2 和HTTP3 是完全不同的协议。

当然,现在 HTTP 服务器已经很少见了。 HTTPS 就是它的所在,这也完全不同。

【讨论】:

  • 我有一个简单的问题。浏览器如何决定标头的编码?或者他们都认为它是 ASCⅡ。
  • 规范或多或少暗示了整个事物中的所有字节,至少在你到达标题之前,都是 ISO-8859-1,实际上是 ASCII。
猜你喜欢
  • 2021-04-15
  • 2018-09-14
  • 2013-03-09
  • 2016-01-08
  • 2018-09-26
  • 1970-01-01
  • 2015-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多