Tomcat 9 Http/2 "Error reading request, ignored"
Tomcat 9 Http/2 "Error reading request, ignored"
我正在使用 tomcat 9.0.5(jdk-9.0.4+11) 来满足我的请求,这些请求还为持久连接启用了 Http/2,我的客户端也使用java 的相同版本,我需要从客户端打开到服务器的持久连接并无限期地重复使用。我可以从客户端成功连接到我的服务器并发送请求(Post with requestBody)但是在 3 个请求(恰好 3 个)之后服务器抛出如下异常,
org.apache.coyote.AbstractProtocol$ConnectionHandler.process Error
reading request, ignored java.lang.NullPointerException at
org.apache.coyote.http2.HpackDecoder.handleIndex(HpackDecoder.java:270)
at org.apache.coyote.http2.HpackDecoder.decode(HpackDecoder.java:111)
at
org.apache.coyote.http2.Http2Parser.readHeaderPayload(Http2Parser.java:418)
at
org.apache.coyote.http2.Http2Parser.readHeadersFrame(Http2Parser.java:252)
at org.apache.coyote.http2.Http2Parser.readFrame(Http2Parser.java:97)
at org.apache.coyote.http2.Http2Parser.readFrame(Http2Parser.java:69)
at
org.apache.coyote.http2.Http2UpgradeHandler.upgradeDispatch(Http2UpgradeHandler.java:313)
at
org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54)
at
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53)
at
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754)
at
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1376)
at
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:844)
所以一个连接只为三个请求打开,之后服务器在这个异常时关闭连接。
p.s:我正在使用 httpclient-5(beta) 从我的客户端建立持久连接。
如果 queryParam/requestBody 是静态内容,连接将保持持久。但是,如果 queryParam/requestBody 有一些动态内容(如时间戳),则连接因上述错误而关闭 我不知道 post 主体中的数据与 tcp 连接[=15] 之间的关系=]
我不能 post 我的请求正文,因为它违反了政策我会 post 在屏蔽我所有的请求参数之后,我的请求看起来像这样,
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 Header 压缩算法。因此,错误消息表明您的 HTTP headers.
存在问题
HTTP/1 对格式错误的 HTTP headers 非常宽容,但 HTTP/2 更为严格。额外的换行符、开引号、额外的冒号等。都会引起问题。
此外,在 HTTP/2 下,所有请求方法和参数都考虑 HTTP Headers。
因此,HTTP/1中的这个:
GET /page.html HTTP/1.1
Header1: Header1Value
Header2: Header2Value
在HTTP/2中变成这样:
:method: GET
:path: /page.html
Header1: Header1Value
Header2: Header2Value
因此请检查您所有的 header(包括您的路径)是否存在格式错误的请求。
在您的情况下,我们的 :path: header.
中的查询参数编码错误
我正在使用 tomcat 9.0.5(jdk-9.0.4+11) 来满足我的请求,这些请求还为持久连接启用了 Http/2,我的客户端也使用java 的相同版本,我需要从客户端打开到服务器的持久连接并无限期地重复使用。我可以从客户端成功连接到我的服务器并发送请求(Post with requestBody)但是在 3 个请求(恰好 3 个)之后服务器抛出如下异常,
org.apache.coyote.AbstractProtocol$ConnectionHandler.process Error reading request, ignored java.lang.NullPointerException at org.apache.coyote.http2.HpackDecoder.handleIndex(HpackDecoder.java:270) at org.apache.coyote.http2.HpackDecoder.decode(HpackDecoder.java:111) at org.apache.coyote.http2.Http2Parser.readHeaderPayload(Http2Parser.java:418) at org.apache.coyote.http2.Http2Parser.readHeadersFrame(Http2Parser.java:252) at org.apache.coyote.http2.Http2Parser.readFrame(Http2Parser.java:97) at org.apache.coyote.http2.Http2Parser.readFrame(Http2Parser.java:69) at org.apache.coyote.http2.Http2UpgradeHandler.upgradeDispatch(Http2UpgradeHandler.java:313) at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1376) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:844)
所以一个连接只为三个请求打开,之后服务器在这个异常时关闭连接。
p.s:我正在使用 httpclient-5(beta) 从我的客户端建立持久连接。 如果 queryParam/requestBody 是静态内容,连接将保持持久。但是,如果 queryParam/requestBody 有一些动态内容(如时间戳),则连接因上述错误而关闭 我不知道 post 主体中的数据与 tcp 连接[=15] 之间的关系=]
我不能 post 我的请求正文,因为它违反了政策我会 post 在屏蔽我所有的请求参数之后,我的请求看起来像这样,
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 Header 压缩算法。因此,错误消息表明您的 HTTP headers.
存在问题HTTP/1 对格式错误的 HTTP headers 非常宽容,但 HTTP/2 更为严格。额外的换行符、开引号、额外的冒号等。都会引起问题。
此外,在 HTTP/2 下,所有请求方法和参数都考虑 HTTP Headers。
因此,HTTP/1中的这个:
GET /page.html HTTP/1.1
Header1: Header1Value
Header2: Header2Value
在HTTP/2中变成这样:
:method: GET
:path: /page.html
Header1: Header1Value
Header2: Header2Value
因此请检查您所有的 header(包括您的路径)是否存在格式错误的请求。
在您的情况下,我们的 :path: header.
中的查询参数编码错误