Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何将Socks 5代理与Apache HTTP客户端4一起使用?_Java_Dns_Apache Httpclient 4.x_Socks - Fatal编程技术网

Java 如何将Socks 5代理与Apache HTTP客户端4一起使用?

Java 如何将Socks 5代理与Apache HTTP客户端4一起使用?,java,dns,apache-httpclient-4.x,socks,Java,Dns,Apache Httpclient 4.x,Socks,我正在尝试创建一个应用程序,通过ApacheHC4通过SOCKS5代理发送HTTP请求。 我无法使用应用程序全局代理,因为应用程序是多线程的(我需要为每个HttpClient实例使用不同的代理)。我没有发现袜子5使用HC4的例子。如何使用它?SOCK是TCP/IP级别的代理协议,而不是HTTP。HttpClient开箱即用不支持它 可以使用自定义连接套接字工厂定制HttpClient以通过SOCKS代理建立连接 编辑:更改为SSL而不是普通套接字 Registry<ConnectionSo

我正在尝试创建一个应用程序,通过ApacheHC4通过SOCKS5代理发送
HTTP
请求
我无法使用应用程序全局代理,因为应用程序是多线程的(我需要为每个
HttpClient
实例使用不同的代理)。我没有发现袜子5使用HC4的例子。如何使用它?

SOCK是TCP/IP级别的代理协议,而不是HTTP。HttpClient开箱即用不支持它

可以使用自定义连接套接字工厂定制HttpClient以通过SOCKS代理建立连接

编辑:更改为SSL而不是普通套接字

Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", PlainConnectionSocketFactory.INSTANCE)
        .register("https", new MyConnectionSocketFactory(SSLContexts.createSystemDefault()))
        .build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);
CloseableHttpClient httpclient = HttpClients.custom()
        .setConnectionManager(cm)
        .build();
try {
    InetSocketAddress socksaddr = new InetSocketAddress("mysockshost", 1234);
    HttpClientContext context = HttpClientContext.create();
    context.setAttribute("socks.address", socksaddr);

    HttpHost target = new HttpHost("localhost", 80, "http");
    HttpGet request = new HttpGet("/");

    System.out.println("Executing request " + request + " to " + target + " via SOCKS proxy " + socksaddr);
    CloseableHttpResponse response = httpclient.execute(target, request, context);
    try {
        System.out.println("----------------------------------------");
        System.out.println(response.getStatusLine());
        EntityUtils.consume(response.getEntity());
    } finally {
        response.close();
    }
} finally {
    httpclient.close();
}

上面的答案非常有效,除非你的国家也毒害了DNS记录。很难说Java“在通过代理连接时不要使用我的DNS服务器”,如以下两个问题所述:

这对于ApacheHttpClient来说也很困难,因为它还尝试在本地解析主机名。通过对上述代码进行一些修改,可以解决这一问题:

static class FakeDnsResolver implements DnsResolver {
    @Override
    public InetAddress[] resolve(String host) throws UnknownHostException {
        // Return some fake DNS record for every request, we won't be using it
        return new InetAddress[] { InetAddress.getByAddress(new byte[] { 1, 1, 1, 1 }) };
    }
}

static class MyConnectionSocketFactory extends PlainConnectionSocketFactory {
    @Override
    public Socket createSocket(final HttpContext context) throws IOException {
        InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);
        return new Socket(proxy);
    }

    @Override
    public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress,
            InetSocketAddress localAddress, HttpContext context) throws IOException {
        // Convert address to unresolved
        InetSocketAddress unresolvedRemote = InetSocketAddress
                .createUnresolved(host.getHostName(), remoteAddress.getPort());
        return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context);
    }
}

static class MySSLConnectionSocketFactory extends SSLConnectionSocketFactory {

    public MySSLConnectionSocketFactory(final SSLContext sslContext) {
        // You may need this verifier if target site's certificate is not secure
        super(sslContext, ALLOW_ALL_HOSTNAME_VERIFIER);
    }

    @Override
    public Socket createSocket(final HttpContext context) throws IOException {
        InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);
        return new Socket(proxy);
    }

    @Override
    public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress,
            InetSocketAddress localAddress, HttpContext context) throws IOException {
        // Convert address to unresolved
        InetSocketAddress unresolvedRemote = InetSocketAddress
                .createUnresolved(host.getHostName(), remoteAddress.getPort());
        return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context);
    }
}

publicstaticvoidmain(字符串[]args)引发异常{
Registry reg=RegistryBuilder.create()
.register(“http”,新的MyConnectionSocketFactory())
.register(“https”,新的MySSLConnectionSocketFactory(SSLContexts.createSystemDefault()).build();
PoolightPClientConnectionManager cm=新的PoolightPClientConnectionManager(reg,new FakeDnsResolver());
CloseableHttpClient httpclient=HttpClients.custom().setConnectionManager(cm.build();
试一试{
InetSocketAddress socksaddr=新的InetSocketAddress(“mysockshost”,1234);
HttpClientContext=HttpClientContext.create();
context.setAttribute(“socks.address”,socksaddr);
HttpGet请求=新建HttpGet(“https://www.funnyordie.com");
System.out.println(“通过SOCKS代理执行请求”+请求+”+socksaddr);
CloseableHttpResponse response=httpclient.execute(请求,上下文);
试一试{
System.out.println(“--------------------------------------------------------”;
System.out.println(response.getStatusLine());
int i=-1;
InputStream=response.getEntity().getContent();
而((i=stream.read())!=-1){
系统输出打印((字符)i);
}
使用(response.getEntity());
}最后{
response.close();
}
}最后{
httpclient.close();
}
}

灵感来自@oleg的答案。您可以创建一个实用程序,该实用程序为您提供了一个正确配置的CloseableHttpClient,并且对如何调用它没有特殊限制

您可以使用ConnectionSocketFactory中的ProxySelector来选择代理

用于构造CloseableHttpClient实例的实用程序类:

import org.apache.http.HttpHost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpCoreContext;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.*;

public final class HttpHelper {
    public static CloseableHttpClient createClient()
    {
        Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", ProxySelectorPlainConnectionSocketFactory.INSTANCE)
                .register("https", new ProxySelectorSSLConnectionSocketFactory(SSLContexts.createSystemDefault()))
                .build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);
        return HttpClients.custom()
                .setConnectionManager(cm)
                .build();
    }

    private enum ProxySelectorPlainConnectionSocketFactory implements ConnectionSocketFactory {
        INSTANCE;

        @Override
        public Socket createSocket(HttpContext context) {
            return HttpHelper.createSocket(context);
        }

        @Override
        public Socket connectSocket(int connectTimeout, Socket sock, HttpHost host, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpContext context) throws IOException {
            return PlainConnectionSocketFactory.INSTANCE.connectSocket(connectTimeout, sock, host, remoteAddress, localAddress, context);
        }
    }

    private static final class ProxySelectorSSLConnectionSocketFactory extends SSLConnectionSocketFactory {
        ProxySelectorSSLConnectionSocketFactory(SSLContext sslContext) {
            super(sslContext);
        }

        @Override
        public Socket createSocket(HttpContext context) {
            return HttpHelper.createSocket(context);
        }
    }

    private static Socket createSocket(HttpContext context) {
        HttpHost httpTargetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST);
        URI uri = URI.create(httpTargetHost.toURI());
        Proxy proxy = ProxySelector.getDefault().select(uri).iterator().next();
        return new Socket(proxy);
    }
}

如果您知道哪些URI需要转到代理,还可以使用低层ProxySelector:对于每个套接字连接,您可以决定要使用哪些代理

它看起来像这样:

public class MyProxySelector extends ProxySelector {
        ...

        public java.util.List<Proxy> select(URI uri) {
        ...
          if (uri is what I need) {
             return list of my Proxies
          }
        ...
        }
        ...
}
 

好的,谢谢。我尝试使用此代码,但我的目标主机是https。如果我将“https”作为方案传递给HttpHost构造函数,它会说不支持方案“https”。如果我传递“http”,它会说响应无效(因为我认为它是SSL),这并没有多大区别,因为SOCKS是TCP/IP级别的协议。请参阅更新的代码片段
HttpClientContext=HttpClientContext.create()
未使用直接复制粘贴您的代码,一开始它对我不起作用。然后我意识到,在我的例子中,我必须在
http
上注册一个定制的基于SOCK的
PlainConnectionSocketFactory
,然后它才能工作。如果其他人也有同样的问题,请在此处发布。是否可以使用socks5代理进行身份验证?我尝试使用
CredentialsProvider
,但没有成功。httpclient似乎忽略了提供的凭据,而是使用我的本地用户名。这是我所发现的最有用的信息之一。任何想通过SOCKS代理使用HttpClient并需要让SOCKS代理解析主机名的人,都可以这样做。@b10y代码中有一个错误。我发布了一个新问题。你能看一下吗?
import org.apache.http.HttpHost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpCoreContext;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.*;

public final class HttpHelper {
    public static CloseableHttpClient createClient()
    {
        Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", ProxySelectorPlainConnectionSocketFactory.INSTANCE)
                .register("https", new ProxySelectorSSLConnectionSocketFactory(SSLContexts.createSystemDefault()))
                .build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);
        return HttpClients.custom()
                .setConnectionManager(cm)
                .build();
    }

    private enum ProxySelectorPlainConnectionSocketFactory implements ConnectionSocketFactory {
        INSTANCE;

        @Override
        public Socket createSocket(HttpContext context) {
            return HttpHelper.createSocket(context);
        }

        @Override
        public Socket connectSocket(int connectTimeout, Socket sock, HttpHost host, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpContext context) throws IOException {
            return PlainConnectionSocketFactory.INSTANCE.connectSocket(connectTimeout, sock, host, remoteAddress, localAddress, context);
        }
    }

    private static final class ProxySelectorSSLConnectionSocketFactory extends SSLConnectionSocketFactory {
        ProxySelectorSSLConnectionSocketFactory(SSLContext sslContext) {
            super(sslContext);
        }

        @Override
        public Socket createSocket(HttpContext context) {
            return HttpHelper.createSocket(context);
        }
    }

    private static Socket createSocket(HttpContext context) {
        HttpHost httpTargetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST);
        URI uri = URI.create(httpTargetHost.toURI());
        Proxy proxy = ProxySelector.getDefault().select(uri).iterator().next();
        return new Socket(proxy);
    }
}
import com.okta.tools.helpers.HttpHelper;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;

public class Main {
    public static void main(String[] args) throws IOException {
        URI uri = URI.create("http://example.com/");
        HttpGet request = new HttpGet(uri);
        try (CloseableHttpClient closeableHttpClient = HttpHelper.createClient()) {
            try (CloseableHttpResponse response = closeableHttpClient.execute(request)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                System.out.println(EntityUtils.toString(response.getEntity()));
            }
        }
    }
}
public class MyProxySelector extends ProxySelector {
        ...

        public java.util.List<Proxy> select(URI uri) {
        ...
          if (uri is what I need) {
             return list of my Proxies
          }
        ...
        }
        ...
}
 
public static void main(String[] args) {
        MyProxySelector ps = new MyProxySelector(ProxySelector.getDefault());
        ProxySelector.setDefault(ps);
        // rest of the application
}