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

时间:2011-09-14 08:43:19

标签: java sockets http proxy

我需要访问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://”,所以它找不到它,并以“Connection refused”结束。奇怪的是select()方法在执行以“Connection refused”结束之前被调用了4次。

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:4)

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

ProxySelector的快速摘要

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

HttpURLConnection类

HTTPUrlConnection的一个实例将多次检查默认的ProxySelector:1st用于选择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,以便在以与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() );

答案 1 :(得分:2)

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

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

client.getHostConfiguration().setProxy(proxyHost, proxyPort);

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