【问题标题】:Tomcat 9 Http/2 "Error reading request, ignored"Tomcat 9 Http/2“错误读取请求,被忽略”
【发布时间】:2018-12-06 10:25:45
【问题描述】:

我正在使用 tomcat 9.0.5(jdk-9.0.4+11) 来处理我的请求,这些请求也启用了 Http/2 以实现持久连接,并且我的客户端也使用相同版本的 java,我需要打开一个持久连接从客户端连接到服务器并无限期地重用。我可以从客户端成功连接到我的服务器并发送请求(使用 requestBody 发布),但是在 3 个请求(正好 3 个)之后,服务器抛出如下异常,

org.apache.coyote.AbstractProtocol$ConnectionHandler.process 错误 读取请求,忽略 java.lang.NullPointerException org.apache.coyote.http2.HpackDecoder.handleIndex(HpackDecoder.java:270) 在 org.apache.coyote.http2.HpackDecoder.decode(HpackDecoder.java:111) 在 org.apache.coyote.http2.Http2Parser.readHeaderPayload(Http2Parser.java:418) 在 org.apache.coyote.http2.Http2Parser.readHeadersFrame(Http2Parser.java:252) 在 org.apache.coyote.http2.Http2Parser.readFrame(Http2Parser.java:97) 在 org.apache.coyote.http2.Http2Parser.readFrame(Http2Parser.java:69) 在 org.apache.coyote.http2.Http2UpgradeHandler.upgradeDispatch(Http2UpgradeHandler.java:313) 在 org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54) 在 org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) 在 org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754) 在 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1376) 在 org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 在 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 在 org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 在 java.base/java.lang.Thread.run(Thread.java:844)

因此,只有三个请求打开一个连接,之后服务器会在此异常情况下关闭连接。

p.s:我正在使用 httpclient-5(beta) 从我的客户端建立持久连接。 如果 queryParam/requestBody 是静态内容,则连接保持持久。但是,如果 queryParam/requestBody 有一些动态内容(如时间戳),则连接因上述错误而关闭,我不知道 post body 中的数据与 tcp 连接之间的关系

我无法发布我的请求正文,因为这违反了我将在屏蔽所有请求参数后发布的政策,我的请求将如下所示,

String postBody = "<?xml version=\"1.0\" standalone=\"no\"?>\n" + 
                "<XX xxx=\"1000000005011\" xxx=\"true\" xxx=\"false\" xxx=\"0\" xxx=\"P|TA|D|J|M\" xxx=\"\" xxx=\"\" xxx=\"false\" xxx=\"false\" xxx=\"1\" xxx=\"true\" xxx=\"false\" xxx=\"xxx\" xxx=\"8265\"  xxx=\"true\" avgDnsTime=\"null\" xxx=\"false\" xxx=\"EVAL_USER\" xxx=\"1000000000011\" xxx=\"2\" xxx=\"true\" xxx=\"http://localhost:8080/app/xxx\" xxx=\"true\" xxx=\"false\" xxx=\"av_xxx\" ut=\"1528453675150\" xxx=\"URL\" xxx=\"70\" time=\""+(System.currentTimeMillis()+"")+"\" xxx=\"1440\" xxx=\"48\" xxx=\"1\" xxx=\"1\" postUrl=\"xxx.com:8443\">\n" + 
                "<XXX xxx=\"\" xxx=\"\" xxx=\"false\" xxx=\"\" xxx=\"1000000005011\" xxx=\"60\" xxx=\"\" xxx=\"127.0.0.1\" xxx=\"\" xxx=\"false\" xxx=\"\" xxx=\"default\" xxx=\"\" xxx=\"\" xxx=\"\" xxx=\"false\" xxx=\"false\" xxx=\"false\" xxx=\"http://www.example.com\" xxx=\"\" xxx=\"\" xxx=\"false\" m=\"G\" xxx=\"0\" xxx=\"\" xxx=\"\" t=\"30\" xxx=\"English\"><XD></XD><XH xxx=\"\" xxx=\"_sep_\" xxx=\"\"/><XI xxx=\"\" xxx=\"\"/>\n" + 
                "</XXX>\n" + 
                "</XX>";

如果有人对此异常有任何想法,请提供帮助

TIA

【问题讨论】:

  • Hpack 错误提示您发送的标头有问题。 HTTP/2 对这些内容更加严格,因此标题名称中的空格、额外的冒号……等都可能在 HTTP/2 中导致问题,即使您在 HTTP/1 中没有使用它们。您能否列出您的第三个请求的标头(可能暂时恢复为 HTTP/1)?
  • 我没有发送任何标头,可能是默认标头???仍然为什么它在三个请求之后失败了???另请注意,如果参数或请求正文包含时间戳等任何内容,它会失败,否则静态内容没关系...
  • 因为您的动态内容返回了一些错误的标题,但您的静态内容没有?而且您只在第三个请求中要求动态内容?这是我最好的猜测。在 HTTP/1 下可以正常工作吗?
  • 不,我在所有请求中发送动态内容,每个请求的时间戳都在不断变化。是的,它在 http1.1 下工作,现在升级到 http/2
  • 你说“如果 queryParam/requestBody 是静态内容”它可以工作。您还说您“在所有请求中发送动态内容”?!?我用我所拥有的有限信息给出了我最好的猜测。工作请求和非工作请求之间明显不同。如果您希望任何人能够为您提供更多帮助,您需要展示这两个不同的请求。

标签: tomcat http2 tomcat9 apache-httpclient-5.x


【解决方案1】:

如 cmets 中所述

HPACK 是 HTTP/2 中使用的 HTTP Header Compression 算法。因此,错误消息表明您的 HTTP 标头存在问题。

HTTP/1 对格式错误的 HTTP 标头非常宽容,但 HTTP/2 更加严格。额外的换行符、开引号、额外的冒号……等等。都会引起问题。

此外,在 HTTP/2 下,所有请求方法和参数都被视为 HTTP 标头。

所以,这在 HTTP/1 中:

GET /page.html HTTP/1.1
Header1: Header1Value
Header2: Header2Value

在 HTTP/2 中变成这样:

:method: GET
:path: /page.html
Header1: Header1Value
Header2: Header2Value

因此请检查您的所有标头(包括您的路径)是否存在格式错误的请求。

在您的情况下,这是我们 :path: 标头中编码错误的查询参数。

【讨论】:

  • 是的,正如我在 cmets 中所说,您的建议指导我以正确的方式调试和解决问题,谢谢 :)
猜你喜欢
  • 2017-01-27
  • 2020-01-20
  • 1970-01-01
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-03
相关资源
最近更新 更多