首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HttpClient :通过代理发送的http 2请求没有升级头

HttpClient :通过代理发送的http 2请求没有升级头
EN

Stack Overflow用户
提问于 2022-04-30 13:15:08
回答 1查看 499关注 0票数 0

因此,我正在管理一家公司http服务器,并已被要求升级服务器以支持使用http 2协议的代理请求。

这是测试客户端。我在jdk 17中使用HttpClient,下面是测试用例。

代码语言:javascript
复制
    public static void main(String[] args)throws Exception
     {
      HttpClient client=HttpClient.newBuilder()
                                  .proxy(ProxySelector.of(new InetSocketAddress("192.168.1.2",1000))) //proxy to 192.168.1.2:1000 
                                  .version(HttpClient.Version.HTTP_2)    //use http 2                      
                                  .build();
      
      //request to 192.168.1.2:2000
      HttpRequest request=HttpRequest.newBuilder(URI.create("http://192.168.1.2:2000/Test.txt"))
                                      .build();
      
      HttpResponse response=client.send(request,BodyHandlers.ofString());
      System.out.println("Status code: " + response.statusCode());                            
      System.out.println("Headers: " + response.headers().map());
      System.out.println("Body: " + response.body());
     } 

我的服务器运行在http 2协议上,我没有得到任何响应。在调试我的服务器上收到的数据包时,如下所示:

代码语言:javascript
复制
    GET http://192.168.1.2:2000/Test.txt HTTP/1.1
    Content-Length: 0
    Host: 192.168.1.2:2000
    User-Agent: Java-http-client/17.0.2

这既不是http 2格式的,也没有我的服务器设计用来解析的任何升级头,这通常是这样的,而不使用代理:

代码语言:javascript
复制
    GET /Test.txt HTTP/1.1
    Connection: Upgrade, HTTP2-Settings
    Content-Length: 0
    Host: 192.168.1.2:2000
    HTTP2-Settings: AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA
    Upgrade: h2c
    User-Agent: Java-http-client/17.0.2

我的服务器是用来解析这个请求的,因为它是升级请求,它包含客户端的http 2设置。

所以,我的问题是当我收到这样的请求时:

代码语言:javascript
复制
     GET http://192.168.1.2:2000/Test.txt HTTP/1.1
     Content-Length: 0
     Host: 192.168.1.2:2000
     User-Agent: Java-http-client/17.0.2
  1. 我是以HTTP1.1或HTTP 2格式返回客户端呢?出现疑问是因为在我的客户端测试用例中,我有明确指定的版本(HTTP_2),但是请求没有升级头,所以我应该以HTTP1.1格式返回吗?
  2. 有没有办法让HttpClient包含升级头,这样我就可以以HTTP2格式返回?

编辑.

为了调试响应,我创建了一个运行在端口1000上的简单TCP服务器,并通过它进行代理。我只需打印在这个代理中接收到的字节,并得到完全相同的输出。

代码语言:javascript
复制
//Test Proxy server running on port 1000. No parsing data simply print and close for debugging purposes
public static void main(String[] args)throws Exception
 {
  try(ServerSocket server=new ServerSocket(1000))
  {
   try(Socket client=server.accept())
   {
    try(InputStream input=client.getInputStream())
    {
     byte[] data=new byte[8196];
     int length=input.read(data);
     System.out.println(new String(data,0,length));
    } 
   } 
  } 
 }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-30 16:20:49

显然,OpenJDK的HttpClient只能向代理发送HTTP/1.1请求。

即使您指定了HttpClient.Version.HTTP_2,因为有一个代理,OpenJDK的HttpClient忽略了您指定的版本,将请求格式化为HTTP/1.1并将其发送给代理。

OpenJDK的HttpClient代理功能非常有限(例如,您不能轻易地使用安全协议与代理通信),因此您可能需要查看不同的HTTP。

免责声明我是Jetty团队的一员。

Jetty的HttpClient支持更灵活的代理配置,因此您可以指定代理所使用的协议(以及它是否安全)。

请注意,您需要代理合作才能获得所需的东西,因为Connection是一个逐跳标头,因此它仅在单个跳(即从客户端到代理)上有效。

代理可以合法地将客户端的HTTP/1.1升级请求接收到HTTP/2,但随后使用HTTP/1.1与服务器对话,从服务器获取HTTP/1.1响应,然后生成一个HTTP/2响应,然后转换为HTTP/2服务器的HTTP/1.1响应:

代码语言:javascript
复制
client                    proxy               server
   | ----  h1+upgrade  ---> |                    |
   |                        | --  h1 request --> |
   |                        | <-- h1 response -- |
   | <-- h1 101 upgrade  -- |
   | <--- h2c response  --- |

支持h2c的代理可以做您想做的事情:

代码语言:javascript
复制
client                     proxy                    server
   | ----  h1+upgradeA  ---> |                        |
   |                         | ---  h1+upgradeB  ---> |
   |                         | <--  h1 101 upgrade -- |
   |                         | <--- h2c response ---- |
   | <--  h1 101 upgrade  -- |
   | <--- h2c response  ---- |

但是,请注意,upgradeA可能与upgradeB完全不同,因为ConnectionUpgrade是逐跳报头,并且代理对于客户端可能有不同的HTTP/2配置(因此也发送不同的HTTP2-Settings报头)。

如果客户机和代理之间的通信是明文的,您必须事先知道代理是否支持h2c,否则客户机将默认为HTTP/1.1 (就像OpenJDK的HttpClient那样)。相反,Jetty的HttpClient可以配置您希望用来与代理对话的协议。

或者,您必须通过TLS使用安全通信,以便客户端和代理能够协商他们想要的协议(例如h2)。

代理也是如此:如果与服务器的通信是明文的(您的情况),代理必须事先知道服务器支持h2c,所以您需要使用该信息配置代理,否则代理很可能默认为HTTP/1.1。

显然,代理必须同时支持HTTP/1.1和HTTP/2。

如果您正在实现代理,将Connection (和其他逐跳报头)复制到服务器上在技术上是错误的,但是它可能在受限、简单的情况下工作。请参阅指定代理应如何删除逐跳标题的RFC 7230的这一部分

FTR,这个测试显示Jetty (客户机和服务器)可以支持客户机、代理和服务器之间的任何协议组合(HTTP/1.1和HTTP/2、明文和安全)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72068831

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档