代理选择器将 URL 的方案从 https:// 更改为 socket://



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

我初始化代理:

ProxySelector.setDefault(new ConfigurableProxySelector(mapping));

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

I'm try to do this:

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

现在,在我的类ConfigurableProxySelector我有选择方法上我有断点:

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

所以,使用HttpClient我做一个请求,它应该被代理和代码停止在断点中选择()方法在ConfigurableProxySelector。

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

因为ProxySelector有"https://"的映射,而不是"socket://",它找不到它,它以"拒绝连接"结束。奇怪的是,select()方法被调用了4次,直到执行结束时显示"Connection refused"。

Apache HTTP Client 3.1将不会本地尊重从默认ProxySelector或用户实现返回的HTTP代理。

ProxySelector快速总结

ProxySelector是一个服务类,它根据方案为给定的URL选择并返回一个合适的代理。例如,如果定义了HTTP代理,则对http://somehost的请求将尝试提供HTTP代理。默认的ProxySelector可以在运行时通过System Properties进行配置,例如http.proxyHosthttp.proxyPort

HTTPUrlConnection

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

HTTP Client 3.1

另一方面,

HC 3.1将永远不会检查http/https方案的默认ProxySelector。但是,当它最终构建原始套接字时,它将稍后检查socket方案—这就是您所看到的请求。这意味着系统属性http.proxyHosthttp.proxyPort无效。对于只有HTTP/HTTPS代理的大多数人来说,这显然不是理想的。

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

HTTPConnectionManager

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

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

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() );

改变方案的不是ProxySelector,而是打开Socket的SocketFactory。如果SocketFactory为空,默认情况下将创建一个SOCKS套接字,它只允许SOCKS代理。我对套接字一无所知,也不能告诉你是否有办法让它与HTTP代理一起工作。

但是使用另一种方法可能会有所帮助,因为Apache HttpClient似乎有自己的方式来配置代理。

client.getHostConfiguration().setProxy(proxyHost, proxyPort);
if (proxyUser != null) {
    client.getState().setProxyCredentials(new AuthScope(proxyHost, proxyPort), 
        new UsernamePasswordCredentials(proxyUser, proxyPassword));
}

最新更新