Netty 3.10.0.FINAL 说 "invalid version format: <!DOCTYPE"

Netty 3.10.0.FINAL says "invalid version format: <!DOCTYPE"

我们使用 Twitter 的 Finagle 客户端,它使用 Netty 作为它的 HTTP 客户端。对于我们的一个 Web 服务调用,我们发现 Netty 无法确定响应的 HTTP 版本,导致

2017-01-13 11:28:13,825 [finagle/netty3-1] WARN com.twitter.finagle.netty3.channel.ChannelStatsHandler ChannelStatsHandler caught an exception
java.lang.IllegalArgumentException: invalid version format: <!DOCTYPE

Netty 的 org.jboss.netty.handler.codec.http.HttpVersion class 试图根据字符串 <!DOCTYPE 确定 HTTP 版本 (HTTP/1.1, HTTP/1.0)。这显然是行不通的。匹配失败导致上面的 IllegalArgumentException。

因此,我的申请根本没有收到回复。 Netty 抛出异常,仅此而已。

我的问题是为什么 Netty 可以使用 <!DOCTYPE 作为 class HttpVersion 中 HTTP 版本匹配的输入。

当我使用 CURL 调用出现此问题的服务时,我得到了具有正确 HTTP 版本的正确响应。下面是 curl returns 的 HTTP headers。我还得到了一个正确的 body,它不以 <!DOCTYPE 开头。它是以 <SOAP-ENVELOPE...

开头的 well-formed SOAP 响应
HTTP/1.1 200 OK
Date: Fri, 13 Jan 2017 12:25:14 GMT
Server: Apache-Coyote/1.1
Content-Type: text/xml;charset=utf-8
Connection: close
Transfer-Encoding: chunked

我的猜测是调用失败是因为某些中间系统 return 的 'broken' 响应,我无法使用 CURL 触发。所以我的第二个问题是,系统是否有可能 return 没有 Http 版本的响应,以及我在这里的思考方向是否正确。

我们在 Finagle 客户端上使用 https 时没有设置 withTls 选项。

我们的解决方案是使用 com.twitter.finagle.Http.withTls(String hostName) 选项创建 Finagle 客户端,并且在我们的特定情况下,还将 Java 的 SSL 上下文设置为 TLS 版本 1.2:

SSLContext sslContext = null;
try {
    sslContext = SSLContext.getInstance("TLSv1.2");
    SSLContext.setDefault(sslContext );
} catch (NoSuchAlgorithmException e) {
    log.error("Failure getting ssl context", e);
}

进行这些更改后,问题消失了。