httpclient 实现 socks 代理

使用的环境

<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.4.1</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.1</version></dependency>

代码及 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<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>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 地址和端口,这里随便写了一个1008InetSocketAddress 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 {@Overridepublic 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());}@Overridepublic 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<ConnectionSocketFactory> 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);}}
........

最后会在 HttpClient 的实现类的doExecute 方法中,根据HttpRoutePlanner 的实现类的 determineRoute 去创建HttpRoute ,最后在由 ClientExecChain 的实现类,去执行 CloseableHttpResponse execute(
            HttpRoute route,
            HttpRequestWrapper request,
            HttpClientContext clientContext,
            HttpExecutionAware execAware) throws IOException, HttpException; 得到响应
以下是 DefaultRoutePlanner 的 determineRoute 方法代码

@Overridepublic 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);}}

HttpClient 实现 socks 代理相关推荐

  1. 给HttpClient添加Socks代理

    本文描述http client使用socks代理过程中需要注意的几个方面:1,socks5支持用户密码授权:2,支持https:3,支持让代理服务器解析DNS: 使用代理创建Socket 从原理上来看 ...

  2. 给OkHttp Client添加socks代理

    Okhttp的使用没有httpClient广泛,网上关于Okhttp设置代理的方法很少,这篇文章完整介绍了需要注意的方方面面. 上一篇博客中介绍了socks代理的入口是创建java.net.Socke ...

  3. SOCKS代理工具EarthWorm、sSoks

    SOCKS代理 常见的网络场景: 服务器在内网中,可以任意访问外部网络 服务器在内网中,可以访问外部用网络,但服务器安装了防火墙来拒绝敏感端口的连接 服务器在内网中,只对外开放了部分端口(例如80端口 ...

  4. autossh配置socks代理

    原理很简单就是用ssh -D建立socks代理,然后把浏览器配置成socks代理就是了.用路由器来做ssh -D的好处是不用在每个设备上(我有一个iphone,两个ipad,一个android手机,n ...

  5. rust 局域网联机_分享自己用 Rust 写的可以直接利用 SOCKS 代理的游戏加速器

    之前分享了一款自己用 Go 写的游戏加速器 IkaGo,但是我也在文章中多次提到,加速器最重要的是线路而不是技术.为了能更好的利用好手上的一些优质的众所周知的 SOCKS 代理,我又开发了一款加速器( ...

  6. 使用代理_工具的使用|MSF搭建socks代理

    目录 搭建代理 添加路由 搭建Socks4a代理 搭建Socks5代理 连接代理 注:通过MSF起的socks代理,经常性的不监听端口,也就导致代理失败.试过好多次都是这样,应该是MSF的一个bug. ...

  7. Android Studio 使用socks代理

    Android Studio 使用socks代理 准备工作 1. 从https://www.privoxy.org/下载Privoxy软件 2. 安装Privoxy 3. 在Privoxy安装目录找到 ...

  8. 代理是什么?(HTTP代理,SOCKS代理)

    本来打算通过UDP53来绕过认证,在准备实现DNS隧道的时候,发现所涉及的内容实在是太多了-(DNS解析原理,域名的原理,隧道技术,代理技术 and so on),每一个知识点都能让我深入去研究一段时 ...

  9. Socks代理是什么意思?有什么用?

    什么是Socks代理 Socks代理:中文名全能代理,就像有很多跳线的转接板,它只是简单地将一端的系统连接到另外一端.支持多种协议,包括http.ftp请求及其它类型的请求.它分socks 4 和so ...

最新文章

  1. php 路由 隐藏index,CI中路由与伪静态、隐藏index.php(十四)
  2. Visual Studio下的PHP开发工具VS.PHP初探
  3. Android 性能测试初探(一)
  4. SAP License:SAP不便解决的问题之六——采购组在审批策略中的作用
  5. linux 内核优化
  6. win7 更新失败解决方案一
  7. 轻松提高Win2003的运行速度
  8. 物流管理毕业论文题目【510个】
  9. 电磁兼容EMC标准 CISPR 22:EN 55022
  10. png转iconfont_IconFont|阿里巴巴矢量图标库
  11. Java泛型入门篇: 泛型类、泛型接口以及泛型方法
  12. 小白学统计|面板数据分析与Stata应用笔记(一)
  13. 提取【酷我音乐MP3】外链url完整地址--可用于做背景音乐
  14. python爬取链家_通过Python爬取链家所有房源和小区信息
  15. Web前端零基础入门HTML5+CSS3学习笔记补充
  16. Hibernate框架简介④
  17. OC和Swift语言的区别
  18. 克服浮躁_如果您从事技术工作,那就克服自己
  19. adguard home上网慢_AdGuardHome最新版本DNS设置负载均衡设置讨论:哪种设置快
  20. SpringBoot 中定时执行注解(@Scheduled、@EnableScheduling)

热门文章

  1. python 蟒蛇程序详解_软件测试学习教程——【大蟒蛇】python基础
  2. Python与医疗图像3
  3. RFID医疗耗材柜管理系统中的解决方案
  4. as转html5工具,HTML5 Convas APIs方法详解
  5. document server java_Readme.md · ct_java/DocumentServer - Gitee.com
  6. 手把手教你用 pyecharts 制作日历图
  7. IText导出PDF添加图片,解决中文问题
  8. 2020年中国科技行业最可能发生的38件事
  9. SpringMVC jdbctemplate实现底层架构封装
  10. Attribute-aware Pedestrian Detection in a Crow