ProxySelector 将 URL 的方案从 https:// 更改为 socket://

2023-12-03

我需要访问 Facebook,但所有传出通信都在我们的服务器上被阻止,因此我必须使用代理。

我用以下方法初始化代理:

ProxySelector.setDefault(new ConfigurableProxySelector(mapping));

代理类型是 HTTP,代理主机和端口正在工作(通过简单的 wget 测试确认)。

我正在尝试这样做:

HttpClient httpClient = new HttpClient();
HttpMethod method = new GetMethod("https://graph.facebook.com:443");

int status = httpClient.executeMethod(method);

现在,在我的 ConfigurableProxySelector 类中,我有 select 方法,在该方法上有断点:

public List<Proxy> select(URI uri) {
...
}

因此,我使用 HttpClient 发出一个请求,该请求应该被代理,并且代码在 ConfigurableProxySelector 中的 select() 方法中的断点处停止。

但奇怪的是 uri.scheme = "socket" 和 .toString() 给出的是 "socket://graph.facebook.com:443" 而不是 "https://graph.facebook.com:443"。

因为 ProxySelector 有“https://”的映射,但没有“socket://”的映射,所以它找不到它,并以“连接被拒绝”结束。奇怪的是,在执行以“连接被拒绝”结束之前,select()方法被调用了4次。

任何帮助,将不胜感激。


Apache HTTP Client 3.1 本身不会支持从默认 ProxySelector 或用户实现返回的 HTTP 代理。

ProxySelector 快速总结

ProxySelector 是一个服务类,它根据其方案为给定 URL 选择并返回合适的代理。例如,请求http://somehost如果已定义,将尝试提供 HTTP 代理。默认的ProxySelector可以在运行时使用系统属性进行配置,例如http.proxyHost and http.proxyPort.

HTTPUrl连接

HTTPUrlConnection 的实例将多次检查默认的 ProxySelector:第一次选择http or https,然后当它构建原始 tcp 套接字时,使用socket方案。 SOCKS 代理可用于代理原始 tcp 套接字,但在企业环境中并不常见,因此原始 tcp 套接字通常不会接收代理。

HTTP 客户端 3.1

另一方面,HC 3.1 将永远不要检查默认的 ProxySelectorhttp/https schemes。不过,稍后它会检查socket最终构建原始套接字时的方案 - 这是您看到的请求。这意味着系统属性http.proxyHost and http.proxyPort是无效的。对于大多数只有 HTTP/HTTPS 代理的人来说,这显然并不理想。

要解决此问题,您有两个选择:在每个 HC 3.1 连接上定义代理或实施您自己的 HC 3.1 HTTPConnectionManager。

HTTP连接管理器

HTTPConnectionManager 负责为 HC 3.1 客户端建立连接。

可以扩展默认的 HC 3.1 HTTPConnectionManager,以便在以与 HTTPUrlConnection 相同的方式构建请求时从 ProxySelector(默认或自定义)查找合适的代理:

public class MyHTTPConnectionManager extends SimpleHttpConnectionManager {
@Override
public HttpConnection getConnectionWithTimeout(
        HostConfiguration hostConfiguration, long timeout) {
    HttpConnection hc = super.getConnectionWithTimeout(hostConfiguration, timeout);

    try {
        URI uri = new URI( hostConfiguration.getHostURL());
        List<Proxy> hostProxies =  ProxySelector.getDefault().select(uri);
        Proxy Proxy = hostProxies.get(0);

        InetSocketAddress sa = (InetSocketAddress) Proxy.address();
        hc.setProxyHost(sa.getHostName());
        hc.setProxyPort(sa.getPort());

    } catch (URISyntaxException e) {
        return hc;
    }   
    return hc;
}
}

然后,当您创建 HC 3.1 客户端时,使用新的连接管理器:

HttpClient client = new HttpClient(new MyHTTPConnectionManager() );
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ProxySelector 将 URL 的方案从 https:// 更改为 socket:// 的相关文章

随机推荐