开发技巧-Java通过HttpProxy实现穿越
需求描述
在正常的项目开发需求中,连接远程服务器的场景一般有二:
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代理及端口,如下:
1 2 3 4 5 6 7 | 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); |
方式二:使用Proxy对象,在建立连接时注入到URLConnection即可:
1 2 3 4 5 6 | // 初始化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头:
1 2 3 4 | 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接口,并注入为全局验证器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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()); } } |
在执行连接之前注入校验实例:
1 2 | MyAuthenticator auth = new MyAuthenticator(proxyUser, proxyPass); Authenticator.setDefault(auth); |
实例代码
入口类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | /** * 网络代理测试 * * <pre> * 设置代理主机及端口:系统变量(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); } } |
校验器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /** * 实现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类是否正确设置。

作者: 美码师(zale)
出处: http://www.cnblogs.com/littleatp/, 如果喜欢我的文章,请关注我的公众号
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文链接 如有问题, 可留言咨询.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?