Polk
Polk

在沪务工的Polk、互拍👏👏👏

[技术]JAVA通过本地VPN-SOCKS代理请求外网

这个问题困扰几个礼拜的了,倒不是难而是根本没空查资料,也就大陆的用户使用VPN访问matters时会有此问题,记录一下。

现象是这样的:
1、我的mac可以正常通过程序访问matters(当然是开了vpn的)  
2、我windows的http工具也是可以访问matters,比如postman,比如浏览器,比如idea自带的http工具(当然也是开了vpn的)
3、问题:唯独windows下通过程序无法访问matters,报下面的错误
org.apache.http.conn.ConnectTimeoutException: Connect to server.matters.news:443 [server.matters.news/103.39.76.66] failed: connect timed out
这导致我的mac已经开启好几周了,有点心疼。。。 
其实问题都能猜到,肯定是程序没有走本地的vpn代理,即使设置了idea的代理也没效果,于是乎我只能搜索一个java访问本地socks代理的方法。  
下面直接上代码了:
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.DnsResolver;
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.entity.StringEntity;
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 javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.util.Map;
import java.util.Set;

public class HttpProxyUtil {
    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);
        }
    }

    public static String getProxy(String url, Map<String,String> heads) {
        String result = null;
        Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory> create()
                .register("http", new MyConnectionSocketFactory())
                .register("https", new MySSLConnectionSocketFactory(SSLContexts.createSystemDefault())).build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg, new FakeDnsResolver());
        CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(cm).build();
        HttpResponse httpResponse = null;
            InetSocketAddress socksaddr = new InetSocketAddress("127.0.0.1", 10808);
            HttpClientContext context = HttpClientContext.create();
            context.setAttribute("socks.address", socksaddr);

            HttpGet request = new HttpGet(url);

            if(heads!=null){
                Set<String> keySet=heads.keySet();
                for(String s:keySet){
                    request.addHeader(s,heads.get(s));
                }
            }
            System.out.println("Executing request " + request + " via SOCKS proxy " + socksaddr);
        try {
            httpResponse = httpclient.execute(request, context);
            HttpEntity httpEntity=httpResponse.getEntity();
            if(httpEntity!=null){
                result= EntityUtils.toString(httpEntity,"utf-8");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }

    public static String postProxy(String url, Map<String,String> heads, String body) {
        String result = null;
        Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory> create()
                .register("http", new MyConnectionSocketFactory())
                .register("https", new MySSLConnectionSocketFactory(SSLContexts.createSystemDefault())).build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg, new FakeDnsResolver());
        CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(cm).build();
        HttpResponse httpResponse = null;
        InetSocketAddress socksaddr = new InetSocketAddress("127.0.0.1", 10808);
        HttpClientContext context = HttpClientContext.create();
        context.setAttribute("socks.address", socksaddr);

        HttpPost request = new HttpPost(url);

        if(heads!=null){
            Set<String> keySet=heads.keySet();
            for(String s:keySet){
                request.addHeader(s,heads.get(s));
            }
        }
        request.addHeader("Content-Type", "application/json;charset=utf-8"); //添加请求头

        System.out.println("Executing request " + request + " via SOCKS proxy " + socksaddr);
        try {
            request.setEntity(new StringEntity(body,"utf-8"));
            httpResponse = httpclient.execute(request, context);
            HttpEntity httpEntity=httpResponse.getEntity();
            if(httpEntity!=null){
                result= EntityUtils.toString(httpEntity,"utf-8");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }
}
CC BY-NC-ND 2.0 版权声明

喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。

加载中…

发布评论