消除或理解 Jetty 9 的 "IllegalStateException: too much data after closed for HttpChannelOverHttp"

Eliminating or understanding Jetty 9's "IllegalStateException: too much data after closed for HttpChannelOverHttp"

设置

我使用 jaxws-maven-plugin v2.1 生成 Web 服务 class。我还包括以下 Jetty 依赖项:

(问题的版本是9.2.10.v20150310,但除了知道它的Jetty 9之外,问题还超越了Jetty的特定小版本号)。

使用下面的代码,我可以成功发布服务:

System.setProperty("com.sun.net.httpserver.HttpServerProvider",
                   "org.eclipse.jetty.http.spi.JettyHttpServerProvider");

final String url = "http://localhost/SlipperySoap";
final SlipperySoap service = new SlipperySoapImpl();
final Endpoint endpoint = Endpoint.publish(url, service);

问题

时不时地,但在相当规律的基础上,我从 Jetty 收到警告:

badMessage: java.lang.IllegalStateException: too much data after closed for HttpChannelOverHttp@38f120bc{r=1,a=IDLE,uri=-}

这些警告经常分批出现,如下时间戳所示:

08:33:43.510 [pool-1-thread-4641] WARN : HttpParser: badMessage: ...
08:33:47.778 [pool-1-thread-4556] WARN : HttpParser: badMessage: ...
08:33:48.340 [pool-1-thread-4612] WARN : HttpParser: badMessage: ...
08:33:49.037 [pool-1-thread-4567] WARN : HttpParser: badMessage: ...
08:33:49.112 [pool-1-thread-4721] WARN : HttpParser: badMessage: ...
08:33:49.242 [pool-1-thread-4579] WARN : HttpParser: badMessage: ...
08:33:49.344 [pool-1-thread-4698] WARN : HttpParser: badMessage: ...
08:33:49.470 [pool-1-thread-4504] WARN : HttpParser: badMessage: ...
08:33:50.260 [pool-1-thread-4553] WARN : HttpParser: badMessage: ...
08:33:54.834 [pool-1-thread-4721] WARN : HttpParser: badMessage: ...
08:34:01.194 [pool-1-thread-4763] WARN : HttpParser: badMessage: ...
08:34:01.675 [pool-1-thread-4715] WARN : HttpParser: badMessage: ...
08:34:02.262 [pool-1-thread-4504] WARN : HttpParser: badMessage: ...
08:34:02.880 [pool-1-thread-4699] WARN : HttpParser: badMessage: ...
08:34:05.530 [pool-1-thread-4570] WARN : HttpParser: badMessage: ...
08:34:09.634 [pool-1-thread-4570] WARN : HttpParser: badMessage: ...
08:34:10.081 [pool-1-thread-4504] WARN : HttpParser: badMessage: ...
08:34:10.298 [pool-1-thread-4738] WARN : HttpParser: badMessage: ...
08:34:13.508 [pool-1-thread-4688] WARN : HttpParser: badMessage: ...
08:34:23.360 [pool-1-thread-4755] WARN : HttpParser: badMessage: ...
08:34:23.557 [pool-1-thread-4717] WARN : HttpParser: badMessage: ...

我想了解这是否是导致我错过处理这些请求的合法问题,或者这是否是可以抑制和忽略的良性警告。

如果这是一个合法的问题,我可以在服务器端采取什么措施来消除它(或者这是一个行为不端的客户端的问题?)。

请注意,我无法控制连接到此 Web 服务的客户端。因此任何解决方案都必须在服务器端实现。

已经探索过的途径

堆栈溢出

有这个Stack Overflow post ,但是答案都是低质量的,不寻求理解核心问题。我尝试更改 Jetty 默认缓冲区大小,但这并没有缓解问题(这并不让我感到惊讶)。

Google 群组

A Google Groups discussion 建议:

This is just a warning and should be ok. IIRC this happens when a connection is forcefully closed.

这没有提供足够的细节让我确信这是一个良性消息 - 缓冲区中有数据被丢弃而不是被处理,所以我需要了解导致这种情况的原因。 为什么另一端会发送请求,然后在读取响应之前关闭连接?这条消息还有其他解释吗?

码头来源

Jetty source code 是这样说的:

/**
 * Parse until next Event.
 * @return True if an {@link RequestHandler} method was called and it returned true;
 */
public boolean parseNext(ByteBuffer buffer)
{
   ...

   // handle end states
   if (_state==State.END)
   {
     // eat white space
     while (buffer.remaining()>0 && buffer.get(buffer.position())<=HttpTokens.SPACE)
       buffer.get();
   }
   else if (_state==State.CLOSED)
   {
     if (BufferUtil.hasContent(buffer))
     {
       // Just ignore data when closed
       _headerBytes+=buffer.remaining();
       BufferUtil.clear(buffer);
       if (_maxHeaderBytes>0 && _headerBytes>_maxHeaderBytes)
       {
         // Don't want to waste time reading data of a closed request
         throw new IllegalStateException("too much data after closed");
       }
     }
   }
   ...

这又提出了一个问题,为什么状态进展到关闭后还有数据要处理。这是在关闭 TCP 连接之前没有等待读取响应的行为不端客户端的签名吗?

这是客户端发出请求的结果,HTTP 行为意味着交换(请求 and/or 响应)应该关闭连接(请求 header 发起或服务器 header 已启动),但客户端仍在请求后发送内容(其 header 和 body 内容)。

最常见的情况:一个写得不好的客户端期望连接是持久的,但不遵循 http 规范并查看指示连接状态的 headers,然后继续发出另一个请求。

另一种常见情况:写得不好的客户端发送请求 header 和(可选)请求 body,但也发送一些额外的字节超过请求 body。这将被解释为另一个需要处理的请求,但初始交换已关闭连接,使得这些额外字节的解析抛出 "too much data after close"

的警告