HttpClient 实现 socks 代理

HttpClient 实现 socks 代理httpclient 实现 socks 代理 httpclientso 代理相关 创建一个注册了 socks 的 httpclient paramprotoco return p

httpclient 实现 socks 代理

使用的环境

 
   
   
     org.apache.httpcomponents 
    
   
     httpclient 
    
   
     4.4.1 
    
   
   
   
     org.apache.httpcomponents 
    
   
     httpcore 
    
   
     4.4.1 
    
  

代码及 ConnectionSocketFactory 实现类

package xxx; import com.lucas.admin.util.HttpClientUtil; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; 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.ssl.SSLContexts; import org.apache.http.util.EntityUtils; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.Socket; / * @author kzcming * @since 2020/11/19 15:51 */ public class Test { public static void main(String[] args) throws Exception { test("https://www.cnblogs.com/"); } public static void test(String url) throws Exception{ // ConnectionSocketFactory注册 Registry 
  
    reg = RegistryBuilder. 
   
     create() .register("http", new MyConnectionSocketFactory()) .register("https",new MySSLConnectionSocketFactory()).build(); // HTTP客户端连接管理池 PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(reg); CloseableHttpClient httpclient = HttpClients.custom() .setConnectionManager(connManager) .build(); try { // socks代理地址 , socks 地址和端口,这里随便写了一个1008 InetSocketAddress socksaddr = new InetSocketAddress("你的地址", 1008); HttpClientContext context = HttpClientContext.create(); context.setAttribute("socks.address", socksaddr); // 请求目标 HttpGet request = new HttpGet(url); System.out.println("----------------------------------------"); System.out.println("执行请求 :" + request.getRequestLine()); System.out.println("通过代理: " + socksaddr); System.out.println("----------------------------------------"); CloseableHttpResponse response = httpclient.execute(request, context); try { HttpEntity entity = response.getEntity(); System.out.println("----------------------------------------"); System.out.println("返回响应:" + response.getStatusLine()); System.out.println("响应内容:" + EntityUtils.toString(entity)); System.out.println("----------------------------------------"); } finally { response.close(); } } finally { httpclient.close(); } } / * 实现 http 链接的socket 工厂 */ static class MyConnectionSocketFactory extends PlainConnectionSocketFactory { @Override public Socket createSocket(final HttpContext context) throws IOException { InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address"); // socket代理 Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr); return new Socket(proxy); } } / * 实现 https 链接的socket 工厂 */ static class MySSLConnectionSocketFactory extends SSLConnectionSocketFactory { public MySSLConnectionSocketFactory() { super(SSLContexts.createDefault(), getDefaultHostnameVerifier()); } @Override public Socket createSocket(final HttpContext context) throws IOException { InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address"); // // socket代理 Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr); return new Socket(proxy); } } } 
    
  

 说明

  • 为什么非得实现一个ConnectionSocketFactory 类,因为这个类,可以看出来这个类就是底层socket请求的时候,创建socket,请求套接字,指定请求ip和端口的,而 socks 协议是通过 socket 实现的协议,

如果不实现一个 ConnectionSocketFactory 实现类,最后在请求的时候,会直接访问原来网址绑定的ip和端口,实现了这个接口,在请求的时候就相当于在 待请求的目标地址外,包了一层外壳,会先去请求 socks 代理地址 和 端口,

具体详情请看 org.apache.http.impl.conn.DefaultHttpClientConnectionOperator 类的 connect 方法,部分代码如下

public void connect( final ManagedHttpClientConnection conn, final HttpHost host, final InetSocketAddress localAddress, final int connectTimeout, final SocketConfig socketConfig, final HttpContext context) throws IOException { final Lookup 
  
    registry = getSocketFactoryRegistry(context); final ConnectionSocketFactory sf = registry.lookup(host.getSchemeName()); if (sf == null) { throw new UnsupportedSchemeException(host.getSchemeName() + " protocol is not supported"); } final InetAddress[] addresses = host.getAddress() != null ? new InetAddress[] { host.getAddress() } : this.dnsResolver.resolve(host.getHostName()); final int port = this.schemePortResolver.resolve(host); for (int i = 0; i < addresses.length; i++) { final InetAddress address = addresses[i]; final boolean last = i == addresses.length - 1; Socket sock = sf.createSocket(context); sock.setSoTimeout(socketConfig.getSoTimeout()); sock.setReuseAddress(socketConfig.isSoReuseAddress()); sock.setTcpNoDelay(socketConfig.isTcpNoDelay()); sock.setKeepAlive(socketConfig.isSoKeepAlive()); if (socketConfig.getRcvBufSize() > 0) { sock.setReceiveBufferSize(socketConfig.getRcvBufSize()); } if (socketConfig.getSndBufSize() > 0) { sock.setSendBufferSize(socketConfig.getSndBufSize()); } final int linger = socketConfig.getSoLinger(); if (linger >= 0) { sock.setSoLinger(true, linger); } conn.bind(sock); final InetSocketAddress remoteAddress = new InetSocketAddress(address, port); if (this.log.isDebugEnabled()) { this.log.debug("Connecting to " + remoteAddress); } try { sock = sf.connectSocket( connectTimeout, sock, host, remoteAddress, localAddress, context); conn.bind(sock); if (this.log.isDebugEnabled()) { this.log.debug("Connection established " + conn); } return; ........ 
  
  • 如果是http协议的代理 或者 https 协议的代理,则需要在创建 HttpClientBuilder 的时候在 setProxy 方法中指定一个代理,最后会在 build() 创建 HttpClient的时候,根据有无代理,

创建HttpRoutePlanner,创建部分代码如下

........ HttpRoutePlanner routePlannerCopy = this.routePlanner; if (routePlannerCopy == null) { SchemePortResolver schemePortResolverCopy = this.schemePortResolver; if (schemePortResolverCopy == null) { schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE; } if (proxy != null) { routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy); } else if (systemProperties) { routePlannerCopy = new SystemDefaultRoutePlanner( schemePortResolverCopy, ProxySelector.getDefault()); } else { routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy); } } ........
@Override public HttpRoute determineRoute( final HttpHost host, final HttpRequest request, final HttpContext context) throws HttpException { Args.notNull(request, "Request"); if (host == null) { throw new ProtocolException("Target host is not specified"); } final HttpClientContext clientContext = HttpClientContext.adapt(context); final RequestConfig config = clientContext.getRequestConfig(); final InetAddress local = config.getLocalAddress(); HttpHost proxy = config.getProxy(); if (proxy == null) { proxy = determineProxy(host, request, context); } final HttpHost target; if (host.getPort() <= 0) { try { target = new HttpHost( host.getHostName(), this.schemePortResolver.resolve(host), host.getSchemeName()); } catch (final UnsupportedSchemeException ex) { throw new HttpException(ex.getMessage()); } } else { target = host; } final boolean secure = target.getSchemeName().equalsIgnoreCase("https"); if (proxy == null) { return new HttpRoute(target, local, secure); } else { return new HttpRoute(target, local, proxy, secure); } }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/220352.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午8:42
下一篇 2026年3月17日 下午8:42


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号