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已在服务器上就位
- 我想使用连接池来提高延迟
<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);