博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
开发技巧-Java通过HttpProxy实现穿越
阅读量:6351 次
发布时间:2019-06-22

本文共 5027 字,大约阅读时间需要 16 分钟。

需求描述

   
在正常的项目开发需求中,连接远程服务器的场景一般有二:
    1  自家实现的http服务器,api接口都已经约定好;
    2  开发平台服务,通常如新浪、百度云等平台提供的restful接口;
 
    以上的两种场景通过原生的URLConnection或是apache提供的httpclient工具包都可以方便的实现调用。
 
    然而,第三种场景是需要连接国外的开放服务,如google、twitter、tumblr等开放API接口。
    在伟大的gfw关怀下,我们被告知不要随便和陌生人说话...
    好吧,接下来让我们开始实现基于proxy的穿越吧!
 

准备工作

    1  http代理服务器
        建议花点银子买个稳定的VPN,带http代理的那种。
 
    2  外网访问测试
        可以用chrome switchyOmega插件测试一把,不行直接设置IE系统代理
 
    准备完毕,可以开始开发了
 

设计分析

    代理连接实现的关键步骤:

    一、设置代理服务器地址端口

           
方式一:Java支持以System.setProperty的方式设置http代理及端口,如下:
 
System.setProperty("http.proxySet", "true");System.setProperty("http.proxyHost", proxyHost);System.setProperty("http.proxyPort", "" + proxyPort); // 针对https也开启代理System.setProperty("https.proxyHost", proxyHost);System.setProperty("https.proxyPort", "" + proxyPort);

  

       关于Java属性的详细设置可参考:
 
 
         
方式二:使用Proxy对象,在建立连接时注入到URLConnection即可:
        
// 初始化proxy对象Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)); // 创建连接URL u = new URL(url);URLConnection conn = u.openConnection(proxy);

  

        
关于两种方式的比较
         第一种方式更值得推荐,当你采用基于URLConnection封装实现的类库时,采用setProperty的方式则不需要动里面的代码,绿色轻便。
 

    二、实现用户密码校验

     
方式一:将校验信息写入http头,将用户名密码进行base64编码之后设置Proxy-Authorization头:
 
String headerKey = "Proxy-Authorization";String encoded = new String(Base64.encodeBase64((new String(proxyUser + ":" + proxyPass).getBytes())));String headerValue = "Basic " + encoded;conn.setRequestProperty(headerKey, headerValue);
           
    不少资料会推荐这样的方式,但经过测试,
该方式在https的需求场景下无法正常工作
      
 
    方式二:实现Authenticator接口,并注入为全局验证器:
 
public static class MyAuthenticator extends Authenticator {    String userName;    String password; public MyAuthenticator (String userName, String password) {    this.userName = userName;    this.password = password;} /*** 当需要使用密码校验时自动触发*/@Overrideprotected PasswordAuthentication getPasswordAuthentication() {    return new PasswordAuthentication(userName, password.toCharArray());}}
       
     在执行连接之前注入校验实例:
 
MyAuthenticator auth = new MyAuthenticator(proxyUser, proxyPass);Authenticator.setDefault(auth);

  

实例代码

入口类

/** * 网络代理测试 *  * 
 * 设置代理主机及端口:系统变量(https 需同步设置) * 设置代理验证方式:全局代理对象 *  *  * https链接错误: * Unable to tunnel through proxy. Proxy returns "HTTP/1.0 407 Proxy Authentication Required" * 使用全局代理验证解决 *  * 
* * @author tzz * @createDate 2015年7月23日 * */public class ProxyTest { private static String proxyHost = "xxx.xxxxx.com"; private static int proxyPort = 8080; private static String proxyUser = "user"; private static String proxyPass = "pass"; public static void main(String[] args) { String url = "https://www.google.com/"; String content = doProxy(url); System.out.println("Result :===================\n " + content); } /** * 通过系统变量方式实现代理 * * @param url * @return */ public static String doProxy(String url) { // 设置系统变量 System.setProperty("http.proxySet", "true"); System.setProperty("http.proxyHost", proxyHost); System.setProperty("http.proxyPort", "" + proxyPort); // 针对https也开启代理 System.setProperty("https.proxyHost", proxyHost); System.setProperty("https.proxyPort", "" + proxyPort); // 设置默认校验器 setDefaultAuthentication(); //开始请求 try { URL u = new URL(url); URLConnection conn = u.openConnection(); HttpsURLConnection httpsCon = (HttpsURLConnection) conn; httpsCon.setFollowRedirects(true); String encoding = conn.getContentEncoding(); if (StringUtils.isEmpty(encoding)) { encoding = "UTF-8"; } InputStream is = conn.getInputStream(); String content = IOUtils.toString(is, encoding); return content; } catch (Exception e) { e.printStackTrace(); return e.getMessage(); } } /** * 设置全局校验器对象 */ public static void setDefaultAuthentication() { BasicAuthenticator auth = new BasicAuthenticator(proxyUser, proxyPass); Authenticator.setDefault(auth); }}

校验器

/**     * 实现sun.net的代理验证     *      * @author tzz     * @createDate 2015年7月23日     *      */    public static class BasicAuthenticator extends Authenticator {        String userName;        String password;        public BasicAuthenticator(String userName, String password) {            this.userName = userName;            this.password = password;        }        /**         * Called when password authorization is needed. Subclasses should override the default implementation, which returns null.         *          * @return The PasswordAuthentication collected from the user, or null if none is provided.         */        @Override        protected PasswordAuthentication getPasswordAuthentication() {            //System.out.println("DEBUG === use global authentication of password");            return new PasswordAuthentication(userName, password.toCharArray());        }    }

常见问题

 连接时异常
     
Unable to tunnel through proxy. Proxy returns "HTTP/1.0 407 Proxy Authentication Required"
      通常是代理服务器未能读取到验证信息所致,请检查目标url是否为https连接以及全局的Authenticator类是否正确设置。

 

转载于:https://www.cnblogs.com/littleatp/p/4729781.html

你可能感兴趣的文章
iOS开发过程中的心得
查看>>
QOS配置命令
查看>>
linux安装搭建media-wiki
查看>>
使用 MPI for Python 并行化遗传算法
查看>>
widget
查看>>
paramiko安装及使用
查看>>
Java私塾:研磨设计模式 之 访问者模式(Visitor)
查看>>
我的友情链接
查看>>
《Python网络数据采集》读书笔记(六)
查看>>
Linux必学的60个命令
查看>>
iptables 学习笔记 (上)
查看>>
Windows Server 2012 R2 Active Directory(活动目录)实验一
查看>>
android viewpager 无限左右滑动
查看>>
linux下SSH远程连接服务慢解决方案
查看>>
利用mic visual studio 2010 编译器执行wincap获取网络适配器的代码
查看>>
HTML
查看>>
CENTOS7下编译安装PHP-5.4以及配置phpMyAdmin
查看>>
磁盘显示无法访问拒绝访问,里面的资料怎样找到
查看>>
Java之品优购课程讲义_day07(5)
查看>>
Java的新项目学成在线笔记-day3(八)
查看>>