Java MTLS和http客户端连接池使用情况

Java MTLS和http客户端连接池使用情况,java,ssl,tls1.2,apache-httpclient-4.x,mtls,Java,Ssl,Tls1.2,Apache Httpclient 4.x,Mtls,背景 我需要连接到不同客户端的服务器 每个客户端连接都应使用唯一的TLS证书 MTLS已在服务器上就位 我想使用连接池来提高延迟 使用以下http客户端 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.12</version>

背景

  • 我需要连接到不同客户端的服务器
  • 每个客户端连接都应使用唯一的TLS证书
  • MTLS已在服务器上就位
  • 我想使用连接池来提高延迟
使用以下http客户端

<dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.5.12</version>
</dependency>

org.apache.httpcomponents

这个假设是真的吗

你的假设是正确的。HttpClient 4和5能够跟踪与HTTP连接相关联的特定于用户的状态(NTLM上下文、TLS用户标识等),并在重新使用持久连接时将其考虑在内

情景1)

后一个调用应该重用现有连接,只要它与前一个调用共享相同的执行上下文

情景2)

不,不是。请提供显示问题的会话的完整上下文/连线日志,我将尝试找出原因

这个假设是真的吗

你的假设是对的。和连接的连接池的方法都使用名为state的附加参数。此状态参数通常采用用户令牌,如果未进行身份验证,则为
null

只有使用用于将连接释放回连接池的相同用户令牌请求连接时,才能重新使用连接

此机制也适用于SSL客户端证书。成功的SSL握手后,将释放SSL连接以及表示用户令牌的。此令牌还存储在用于请求的
HttpContext
对象中。要在后续HTTP请求中重新使用已释放的连接,还必须重新使用第一个HTTP请求的
HttpContext

情景1

第一个请求触发完整的SSL握手。使用用户令牌释放连接。第二个请求使用一个新的
HttpContext
,它不包含任何用户令牌。因此,池中的连接不能重复使用,并且使用完全握手创建新连接

情景2

如前所述,用户令牌存储在
HttpContext
中。因此,如果您从第一个请求重新使用
HttpContext
,则第二个请求可以重新使用已经存在的连接,即使您使用具有不同连接工厂/客户端证书的不同客户端。如果该连接正在使用中,将使用clientB的连接工厂创建一个新连接

要分离
clientA
clientB
并确保每个客户端只重复使用连接,您必须为每个客户端使用一个
HttpContext
,并为每个请求重复使用上下文:

HttpContext contextA = new HttpClientContext();
clientA.execute(new HttpGet("..."), contextA);
clientA.execute(new HttpGet("..."), contextA);

HttpContext contextB = new HttpClientContext();
clientB.execute(new HttpGet("..."), contextB);

请注意,在会话超时或请求重新协商的情况下,即使重新使用连接,也可能需要完全握手。

我已按照请求在@ok2c处附加了日志。谢谢你的帮助。我可能不太理解你的问题。我可以清楚地看到一个新的连接请求和三个请求的完整TLS握手。我为问题添加了额外的细节,谢谢。我清楚地看到三个不同的连接和三个不同的TLS握手。对不起,我不明白你的问题。是关于第三个消息交换没有重新使用第一个消息交换的连接吗?
poollighttpclientconnectionmanager-连接请求:[路由:{s}->https://server:8443][可用总数:2;分配的路由:2/2;分配的总数:2/20]
第三个请求不包括状态(用户令牌),因此,HttpClient不重新使用现有的持久状态完整连接是绝对正确的。设置TLS上下文的方式有问题。很可能您需要使用不同的TLS会话缓存发出不同的请求,或者使用
SSLSession#invalidate()
手动使TLS会话无效,以防止其恢复。
HttpContext context = new HttpClientContext();
clientA.execute(new HttpGet("..."), context);
clientB.execute(new HttpGet("..."), context);
HttpContext contextA = new HttpClientContext();
clientA.execute(new HttpGet("..."), contextA);
clientA.execute(new HttpGet("..."), contextA);

HttpContext contextB = new HttpClientContext();
clientB.execute(new HttpGet("..."), contextB);