isReady()在关闭状态下返回true-为什么? [英] isReady() returns true in closed state - why?

查看:575
本文介绍了isReady()在关闭状态下返回true-为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ServletOutputStream.isReady() javadoc表示以下内容:

返回: 如果对该ServletOutputStream的写操作将成功,则返回true,否则返回false.

尽管实现了Jetty的ServletOutputStream,但在流处于CLOSED状态的情况下,HttpOutput的表现似乎很混乱.它返回true:

case CLOSED:
    return true;

来源:

所以看来写不可能成功.这种行为背后的原因是什么?

关键事实:关闭调用意味着进行写操作.

CLOSED内部状态指示流/输出的使用情况对该调度已关闭(不是流本身实际上已关闭).

我们如何进入这种状态?某些事件触发了ServletOutputStream.close()(进而又触发了HttpOutput.close()),现在不再允许从当前分派对该流进行写操作.

在关闭"状态下,将发生刷新.

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

HttpOutput也是所有嵌套请求的输出点,例如使用RequestDispatcher中的include(),这将重新打开HttpOutput以在include()中使用,然后再次将其关闭. /p>

一旦HttpOutput被完全彻底地刷新/完成(没有更多的调度,没有更多的写入等),然后完成最后的缓冲区刷新,完成传输编码,重置,回收和返回HttpOutput到HttpConnection以便在下一次交换时使用.

我们可以在代码库中更好地完成javadoc的工作,或者至少使用更有意义的常量和变量名.

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

关于写入时的Jetty EofException(不是JVM EOFException).

一旦ServletOutputStream已关闭以在特定调度上使用,则对write()的进一步调用将导致Jetty EofException.

还有一种EofException的风格,其中违反了您已提交的响应详细信息.

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

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

ServletOutputStream.isReady() javadoc says the following:

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

In spite of that Jetty's ServletOutputStream implementation, HttpOutput seems to behave rather confusing in the case when the stream is in CLOSED state. It returns true:

case CLOSED:
    return true;

Source: HttpOutput.java:1011.

Furthermore, all three write methods in HttpOutput throws EofException when it's CLOSED:

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

So it seems that write can never succeed. What's the reason behind this behavior?

解决方案

Key Fact: A close call implies a write operation.

The CLOSED internal state indicates that usage of the stream/output is CLOSED to that dispatch (not that the stream itself is actually closed).

How did we get into this state? Something has triggered the ServletOutputStream.close() (and in turn HttpOutput.close()) and now no more writes are allowed on that stream from the current dispatch.

In the CLOSED state, a flush occurs.

  • A flush will commit the response
  • A flush will finish writing the various buffers present on the various layers of the exchange / connection / output.
  • If there is an aggregate buffer (for many small writes) it writes that out.
  • If there is a compression layer (gzip) it will force a flush from there as well.
  • Then all of those buffers also go through the Transfer-Encoding layer (eg: chunked).
  • Then the network write occurs.

The HttpOutput is also the one point of output for all nested requests, such as using include() from RequestDispatcher which will reopen the HttpOutput for use during the include() and then close it again.

Once the HttpOutput is fully and completely flushed/finished (no more dispatches, no more writes, etc), then the final buffer flush is done, transfer-encodings are completed, the HttpOutput is reset, recycled, and returned to the HttpConnection for use with the next exchange.

We could do a better job of javadoc'ing that in the codebase, or at least using constants and variable names that make more sense.

Opened https://github.com/eclipse/jetty.project/issues/2687

Regarding the Jetty EofException (not the JVM EOFException) on write.

Once the ServletOutputStream is CLOSED for usage on the specific dispatch, further calls to write() will result in a Jetty EofException.

There is also a flavor of EofException where your committed response details were violated.

Eg: you declared a response Content-Length of say 40MB, but wrote 41MB, you exceeded the capability of that committed response, this is an IOException. And the Servlet spec tells us to throw an IOException in this case.

Jetty will throw the Jetty internal EofException (which extends IOException) to indicate this specific scenario and abort the connection, breaking any connection persistence you may have wanted.

这篇关于isReady()在关闭状态下返回true-为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆