如何从服务器端判断客户端是否支持HTTP/2

5
我正在编写一个分析服务器,将被Web用户使用。其中一个我想测试的参数是他们的浏览器支持情况。请告诉我是否可以获取以下信息以及如何获取:
  • 测试客户端(用户浏览器)是否支持 http/2
  • 测试客户端(用户浏览器)是否支持http/2 pushes,某种方式检测服务器何时发送推送,客户端能否使用它,这可能是一些js测试,或者你告诉我。
  • 测试客户端(用户浏览器)是否支持QUIC,即http/2的UDP版本
2个回答

1
这取决于所使用的Web服务器以及其提供有关连接的详细信息。例如,Apache提供以下变量:https://httpd.apache.org/docs/2.4/mod/mod_http2.html#envvars,其中包括这些变量:
Variable Name:  Value Type:   Description:
HTTP2           flag          HTTP/2 is being used.
H2PUSH          flag          HTTP/2 Server Push is enabled for this connection and also supported by the client.
H2_PUSHED       string        empty or PUSHED for a request being pushed by the server.

所以您可以使用以下LogFormat轻松将其添加到日志文件中:
LogFormat "%h %l %u %t %{ms}T \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %{SSL_PROTOCOL}x %{SSL_CIPHER}x %{Content-Encoding}o %{H2_PUSHED}e" combined

然后从日志文件中查看它是否通过HTTP/2.0提供,并且是否已经PUSHED。例如:

86.1.2.3 - - [11/Jul/2017:22:14:56 +0100] 2 "GET / HTTP/2.0" 200 1700 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 br
86.1.2.3 - - [11/Jul/2017:22:14:56 +0100] 3 "GET /assets/css/common.css HTTP/2.0" 200 5381 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 br PUSHED

这些变量也可用于CGI脚本等。请注意,仅当实际使用HTTP/2时才会设置这些变量。
并非所有的Web服务器像Apache一样容易公开此级别的细节,许多服务器不支持HTTP/2推送,因此可能无法检测到它们自己不支持的协议。
据我所知,没有任何Web浏览器从HTTPS客户端hello消息(当HTTP/2将被协商时)提供这些详细信息,因为大多数浏览器只提供当前连接的详细信息,并且仅在HTTPS会话建立后才提供详细信息。例如,Apache的HTTPS变量在此处给出:http://httpd.apache.org/docs/current/mod/mod_ssl.html#envvars 由于QUIC得到的Web服务器支持较少,因此难以检测。
要从客户端实际检测到所有这些内容更加困难,因为据我所知,这些内容不会暴露给JavaScript。最简单的方法是通过HTTP/2调用一个CGI脚本,该脚本返回Web服务器提供的这些值的结果。
请注意,只有在需要时才会使用推送资源。如果需要但未被推送,则仍将获取它。因此,您对JS测试的想法,可能检测到是否正在使用推送资源,不能确定客户端是否支持推送,因为该资源可能已被获取。

我还不确定后端将使用哪个服务器,所以我只想知道客户端发送给后端的内容,以便后端了解客户端支持的协议。 - Ilya Gazman
这完全取决于你选择的后端暴露的细节,就像我所说的。而且,你无法区分使用了被推送的资源和未经推送获取的相同资源,正如我在答案中提到的那样。除非你根据从后端是否支持推送来改变该资源的内容。 - Barry Pollard
好的,我明白你说的关于推送的事情。 - Ilya Gazman
我检查过并发现协议信息是在ssl握手期间与客户端协商的,而且客户端是启动它的。因此,理论上,当使用客户端hello开始ssl协商时,它应该已经发送了关于是否支持http/2以及是否将使用QUIC的信息,这与您使用的服务器无关,也与其对http/2的支持无关。 - Ilya Gazman
我在答案中添加了一句话来强调这一点。不过看到你已经接受了我的答案,所以非常感谢。 - Barry Pollard
显示剩余2条评论

0

你能做的最好的就是通过用户代理来确定他们的浏览器,然后将其与一些浏览器和功能的数据库进行交叉引用。

当然,用户代理可能会欺骗,但大多数情况下它们会适当地宣布自己。


用户代理并不能告诉您协议的类型。 - Ilya Gazman
2
那是正确的。如果你读了我实际说的话,这就是为什么我说你需要将用户代理与一个数据库进行交叉引用,该数据库说明对于这个用户代理,它支持这些功能。浏览器中没有任何东西可以告诉它的协议。 - samanime
服务器必须能够判断客户端是否支持http/2,否则它不知道在与该客户端通信时使用什么协议。 - Ilya Gazman
你没有错,但用户代理字符串可能会被伪造,或者当前连接不支持HTTP/2的另一个原因,比如未使用HTTPS。 - PHP Guru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接