【问题标题】:isReady() returns true in closed state - why?isReady() 在关闭状态下返回 true - 为什么?
【发布时间】:2018-12-08 14:39:17
【问题描述】:

ServletOutputStream.isReady() javadoc says the following:

返回: 如果写入此 ServletOutputStream 将成功,则返回 true,否则返回 false。

尽管 Jetty 实现了 ServletOutputStream,但当流处于 CLOSED 状态时,HttpOutput 的行为似乎相当混乱。它返回true

case CLOSED:
    return true;

来源:HttpOutput.java:1011

此外,HttpOutput 中的所有三个 write 方法都会在 CLOSED 时抛出 EofException

case CLOSED:
    throw new EofException("Closed");

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

【问题讨论】:

  • 我同意。你有四个明显的错误,写方法抛出EOFException肯定是完全疯狂的。举报他们。

标签: java servlets jetty servlet-3.1


【解决方案1】:

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

CLOSED 内部状态表明流/输出的使用对该调度已关闭(而不是流本身实际上已关闭)。

我们是如何进入这种状态的?某些东西触发了ServletOutputStream.close()(然后是HttpOutput.close()),现在不允许从当前调度对该流进行更多写入。

在 CLOSED 状态下,会发生刷新。

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

HttpOutput 也是所有嵌套请求的一个输出点,例如使用include() from RequestDispatcher 将重新打开HttpOutput 以供include() 期间使用,然后再次关闭它。

一旦HttpOutput 被完全刷新/完成(不再调度、不再写入等),那么最终的缓冲区刷新完成,传输编码完成,HttpOutput 被重置、回收并返回到 HttpConnection 以供下次交换使用。

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

打开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)以指示此特定场景并中止连接,从而破坏您可能想要的任何连接持久性。

【讨论】:

  • 嗯,不完全是。我的意思是“一点”,这意味着对于包含多个嵌套请求的复杂请求,仍然只有 1 个 HttpOutput 实例来管理它。
  • 你不得不承认EofException on write 是一个糟糕的选择。不涉及文件结尾:只是状态转换。它应该类似于ClosedException
  • @JoakimErdfelt:谢谢,这句话是关键。
猜你喜欢
  • 1970-01-01
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多