在 Apache HttpClient 4 应用中,HTTPS 目标并不意味着每条连接都以 TLS 开始。普通 HTTP 代理是通过明文连接到达的,之后 CONNECT 打开隧道,TLS 才向目标方向叠加。

如果自定义连接管理器只注册 https,第一次经过代理的跳转就可能以 UnsupportedSchemeException: http protocol is not supported 失败。

对于 4.5 API,构造该管理器时要同时包含两个工厂:

var registry = RegistryBuilder.<ConnectionSocketFactory>create()
    .register("http", PlainConnectionSocketFactory.getSocketFactory())
    .register("https", tlsFactory)
    .build();

var manager = new PoolingHttpClientConnectionManager(registry);
var client = HttpClients.custom()
    .setConnectionManager(manager)
    .setProxy(new HttpHost("proxy.example.net", 8080, "http"))
    .build();

tlsFactory 是应用现有的 SSLConnectionSocketFactory,带有预期的信任与主机名校验。所示类型属于 Apache 4 的 org.apache.http 包。该片段假定 Java 支持局部变量类型推断;较旧的 Java 源码可以显式写出类型。

把修正后的管理器挂到真正用于请求的客户端上。对于允许的公开 HTTPS 请求且没有代理认证时,HTTP 代理列表中的 HTTP 条目可以填入 HttpHost 的代理地址。配置另一个 builder 不会更新已经构建的客户端。

还要检查 builder 的归属:HttpClientBuilder 的文档说明,显式提供的连接管理器可能覆盖其单独的 SSL 配置输入。应把所需的工厂放进管理器的注册表,而不是假定之后调用 setSSLContext 会替换其内部实现。

这一诊断针对本地方案注册表。代理认证质询或目标被拒绝是更晚出现的不同结果。调查这些响应时,请保留两个工厂注册。

相关文章