isReady() returns 在关闭状态下为真 - 为什么?

isReady() returns true in closed state - why?

ServletOutputStream.isReady() javadoc says the following:

Returns: true if a write to this ServletOutputStream will succeed, otherwise returns false.

尽管 Jetty 的 ServletOutputStream 实现,HttpOutput 在流处于 CLOSED 状态的情况下似乎表现得相当混乱。它returns true:

case CLOSED:
    return true;

来源:HttpOutput.java:1011.

此外,HttpOutput 中的所有三个 write 方法在 CLOSED:

时抛出 EofException
case CLOSED:
    throw new EofException("Closed");

这么看来write永远不可能成功。这种行为背后的原因是什么?

关键事实:关闭调用意味着写入操作。

CLOSED 内部状态表示 stream/output 的 usage 已关闭到该调度(不是流本身实际上已关闭)。

我们是如何进入这种状态的?某些东西触发了 ServletOutputStream.close()(进而 HttpOutput.close()),现在从当前分派开始不再允许对该流进行写入。

在CLOSED状态下,发生flush。

  • 刷新将提交响应
  • 刷新将完成对交换/连接/输出各个层上存在的各种缓冲区的写入。
  • 如果有一个聚合缓冲区(对于许多小的写入)它会写出来。
  • 如果有压缩层 (gzip),它也会强制从那里进行刷新。
  • 然后所有这些缓冲区也通过 Transfer-Encoding 层(例如:分块)。
  • 然后发生网络写入。

HttpOutput也是所有嵌套请求的一个输出点,比如using include() from RequestDispatcher会重新打开HttpOutput以供在include() 然后再次关闭它。

一旦 HttpOutput 完全 flushed/finished(不再发送,不再写入等),最后的缓冲区刷新完成,传输编码完成,HttpOutput 是重置、回收并返回到 HttpConnection 以供下一次交换使用。

我们可以在代码库中更好地编写 javadoc,或者至少使用更有意义的常量和变量名。

已打开https://github.com/eclipse/jetty.project/issues/2687

关于写 Jetty EofException(不是 JVM EOFException)。

一旦 ServletOutputStream 关闭以用于特定调度,进一步调用 write() 将导致 Jetty EofException.

还有一种情况是 EofException 违反了您提交的响应详细信息。

例如:您声明了一个响应 Content-Length,比如 40MB,但写入了 41MB,您超出了该已提交响应的能力,这是一个 IOException。在这种情况下,Servlet 规范告诉我们抛出一个 IOException

Jetty 将抛出 Jetty 内部 EofException(它扩展了 IOException)以指示这种特定情况并中止连接,从而破坏您可能想要的任何连接持久性。