开发技巧-Java通过HttpProxy实现穿越

需求描写叙述

在正常的项目开发需求中。连接远程server的场景一般有二:

1  自家实现的httpserver,api接口都已经约定好。

2  开发平台服务。通常如新浪、百度云等平台提供的restful接口。

以上的两种场景通过原生的URLConnection或是apache提供的httpclient工具包都能够方便的实现调用。

然而,第三种场景是须要连接国外的开放服务,如google、twitter、tumblr等开放API接口。

在伟大的gfw关怀下,我们被告知不要随便和陌生人说话...

好吧,接下来让我们開始实现基于proxy的穿越吧!

准备工作

1  http代理server

建议花点银子买个稳定的VPN,带http代理的那种。

2  外网訪问測试

能够用chrome switchyOmega插件測试一把。不行直接设置IE系统代理

准备完成。能够開始开发了

设计分析

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

一、设置代理server地址port

方式一:Java支持以System.setProperty的方式设置http代理及port,例如以下:

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属性的具体设置可參考:http://docs.oracle.com/javase/6/docs/technotes/guides/net/properties.html

方式二:使用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的方式则不须要动里面的代码,绿色轻便。

二、实现用户password校验

方式一:将校验信息写入http头,将usernamepassword进行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;
}

/**
* 当须要使用密码校验时自己主动触发
*/
@Override
protected PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(userName, password.toCharArray());
}
}

在运行连接之前注入校验实例:

MyAuthenticator auth = new MyAuthenticator(proxyUser, proxyPass);
Authenticator.setDefault(auth);

  

实例代码

入口类

/**
 * 网络代理測试
 *
 * <pre>
 * 设置代理主机及port:系统变量(https 需同步设置)
 * 设置代理验证方式:全局代理对象
 *
 *
 * https链接错误:
 * Unable to tunnel through proxy. Proxy returns "HTTP/1.0 407 Proxy Authentication Required"
 * 使用全局代理验证解决
 *
 * </pre>
 *
 * @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"

一般是代理server未能读取到验证信息所致,请检查目标url是否为https连接以及全局的Authenticator类是否正确设置。

时间: 2024-10-18 15:37:50

开发技巧-Java通过HttpProxy实现穿越的相关文章

Java 8的五大开发技巧

转载:http://geek.csdn.net/news/detail/94219 在Java 9发布之前,我们来分享一些Java 8开发技巧,本文翻译自JetBrains高级开发主管Trisha Geed的Java 8 Top Tips. [以下为译文] 在使用JAVA 8进行开发多年后,结合个人使用IntelliJ IDEA的心得,我总结了以下几个JAVA8技巧供大家参考. Optional Optional 是一个被高度低估的特性,假若能把它运用恰当,其实它是能帮助减少大量的NullPoi

【Java】Web 服务编程技巧与窍门: 在 UDDI 注册中心为 Web 服务注册开发 UDDI Java 应用程序

本技巧建立了一个使用统一描述.发现和集成 (Universal Description, Discovery, and Integration,UDDI) 来注册应用程序级消费的 Web 服务实例.作者提供了详细的代码示例以及基于 Java 的统一描述.发现和集成 (Universal Description, Discovery,and Integration for Java,UDDI4J) API 的扩展 API,通过这些可以使您使用 UDDI 来进行您自己的开发. 0 评论: Andre

webApp前端开发技巧

自Iphone和Android这两个牛逼的手机操作系统发布以来,在互联网界从此就多了一个新的名词-WebApp(意为基于WEB形式的应用程序,运行在高端的移动终端设备). 开发者们都知道在高端智能手机系统中有两种应用程序:一种是基于本地(操作系统)运行的APP:一种是基于高端机的浏览器运行的WebApp,本文将主要讲解后者. WebApp与Native App有何区别呢? Native App: 1.开发成本非常大.一般使用的开发语言为JAVA.C++.Objective-C. 2.更新体验较差

Android开发技巧——自定义控件之自定义属性

Android开发技巧--自定义控件之自定义属性 掌握自定义控件是很重要的,因为通过自定义控件,能够:解决UI问题,优化布局性能,简化布局代码. 上一篇讲了如何通过xml把几个控件组织起来,并继承某个ViewGroup子类,把它们封装起来使用.这是我们接触到的最简单的一种自定制控件了.但许多时候,我们还需要在布局文件中使用它们的时候,能通过属性传入一些值,来影响最终的显示结果. 我们在做项目中经常会遇到的一个情况:一张图片加一个文本的组合.比如充值账户成功之后显示的一个界面,上面是一个表示成功的

WebApp开发技巧大全 看了就明白了

[转载]阅读原文 自Iphone和Android这两个牛逼的手机操作系统发布以来,在互联网界从此就多了一个新的名词-WebApp(意为基于WEB形式的应用程 序,运行在高端的移动终端设备).开发者们都知道在高端智能手机系统中有两种应用程序:一种是基于本地(操作系统)运行的APP:一种是基于高端机的浏览 器运行的WebApp [NativeApp与WebApp的比较] NativeApp 1.开发成本非常大.一般使用的开发语言为JAVA.C++.Objective-C. 2.更新体验较差.同时也比

Android开发技巧——大图裁剪

本篇内容是接上篇<Android开发技巧--定制仿微信图片裁剪控件> 的,先简单介绍对上篇所封装的裁剪控件的使用,再详细说明如何使用它进行大图裁剪,包括对旋转图片的裁剪. 裁剪控件的简单使用 XML代码 使用如普通控件一样,首先在布局文件里包含该控件: <com.githang.clipimage.ClipImageView xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+i

Android开发技巧之viewstub用法详解及实现延迟加载

这一篇是接着上面的include标签的例子来讲的,地址http://blog.csdn.net/jason0539/article/details/26131831 上一篇的布局中间就用了viewstub这个控件,现在来说一下其作用和用法 " ViewStub 是一个不可见的,大小为0的View,最佳用途就是实现View的延迟加载,避免资源浪费,在需要的时候才加载View " 需要注意的是,加载view之后,viewstub本身就会被新加载进来的view替换掉 上代码了,看完就理解了

Android开发技巧——实现可复用的ActionSheet菜单

在上一篇<Android开发技巧--使用Dialog实现仿QQ的ActionSheet菜单>中,讲了这种菜单的实现过程,接下来将把它改成一个可复用的控件库. 本文原创,转载请注明出处: http://blog.csdn.net/maosidiaoxian/article/details/46324941 对于要实现的可复用的控件库,我需要它具备以下两点: 可添加远程依赖(不考虑Eclipse中的使用) 可灵活配置 分离库的实现代码 对于第一点,需要做的就是在Android Studio中新建一

开发技巧----------项目中常量类的定义方式

问题: 有开发经验的同学都知道,常量类是一个最常用的定义数据字典的方式.但是随着项目的开发时间和开发团队的变化经常会出现2中特别苦逼的情况.第一种情况是项目中到处都能看到各种各样的常量类:第二种情况是一个常量类里定义非常多的常量,甚至有的超过100了.这两种情况的缺点估计大家都非常的清楚,第一种代码离散.冗余.维护难:第二种也是维护难,更痛苦的时候用ide的时候很难找到自己需要的常量. 解决办法: 1.使用静态内部类对常量进行分组(可以多级分组,但是建议最多3级) 2.外部文件(这里不讨论) 3