1. 专有云访问公网资源
最近一个部署在专有云的项目上线后,需要访问公网资源,客户专有云环境对外网访问控制比较严格,开放一个代理服务器可访问外网。
2. Linux 上通过Http代理访问
在Linux上需要下载公网的资源,只要指定https_proxy和https_proxy即可,我们测试一下是否可行
#设置http/htts代理
[root@iZvy205enekymwo01x4w3vZ test]# export https_proxy=10.145.9.74:3128
[root@iZvy205enekymwo01x4w3vZ test]# export http_proxy=10.145.9.74:3128
# 查看是否走到代理
[root@iZvy205enekymwo01x4w3vZ test]# curl -v -o /dev/null -s https://www.taobao.com
* About to connect() to proxy 10.145.9.74 port 3128 (#0)
* Trying 10.145.9.74...
* Connected to 10.145.9.74 (10.145.9.74) port 3128 (#0)
* Establish HTTP proxy tunnel to www.taobao.com:443
# 查看请求时间
[root@iZvy205enekymwo01x4w3vZ ~]# curl -o /dev/null -s -w %{time_namelookup}:%{time_connect}:%{time_starttransfer}:%{time_total}:%{speed_download}"\n" https://www.taobao.com
0.000:0.002:0.190:0.286:514182.000
各参数的含义
time_namelookup - DNS服务器解析时间,单位秒
time_connect - client 发出请求,到 c/s 建立TCP 的时间;里面包括 DNS 解析的时间
time_starttransfer - client 发出请求;到 server 响应发出第一个字节开始的时间;包括前面的2个时间
time_total - client 发出请求;到 server 把响应的数据全部发送给 client;并关闭 connect 的时间
speed_download - 下载速率
3. Java应用中使用HTTP代理
在Java应用中,常用的有两种http客户端实现
- Java自带的HttpUrlConnection
- Apache的HttpClient
这两种实现设置代理的方式有一些区别
3.1 HttpUrlConnection代理
3.1.1 设置JVM启动参数
-Dhttp.proxyHost=10.145.9.74 -Dhttp.proxyPort=3128 -Dhttps.proxyHost=10.145.9.74 -Dhttps.proxyPort=3128
该方式会将所有使用HttpUrlConnection做http客户端的请求都走代理,对HttpClient无效。在专有云上使用访问内部资源也会走到代理,这样可能会带来问题。我们需要能控制访问外网的请求走代理,下面我们来看看在代码里如何实现。
3.1.2 Proxy
URL url = new URL("https://www.taobao.com");
Proxy proxy = new Proxy(Proxy.Type.DIRECT.HTTP, new InetSocketAddress("10.145.9.74", 3128));
HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
该方式简单,但是对于已经封装好的二方库,我们没办法去修改代码,JDK提供了一种代理选择机制
3.1.3 ProxySelector
//实现代理选择器,根据域名选择代理服务器
public class MyProxySelector extends ProxySelector {
private List<Proxy> proxyList = Lists.newArrayList(new Proxy(Type.HTTP, InetSocketAddress.createUnresolved("10.145.9.74", 3128)));
private ProxySelector defaultProxy = ProxySelector.getDefault();
@Override
public void connectFailed(URI uri, SocketAddress address, IOException e) {
//代理出错处理
}
@Override
public List<Proxy> select(URI uri) {
String host = uri.getHost().toLowerCase();
if(host.endsWith("taobao.com")){
return proxyList;
}else{
return defaultProxy;
}
}
}
//设置系统默认代理服务器
ProxySelector.setDefault(new MyProxySelector());
ProxySelector机制所有采用HttpUrlConnection实现http的请求都会经过select方法,在这里可以根据URI来决定是否走代理。
对于HttpUrlConnection实现的http请求,ProxySelector可以完美解决,但是Apache HttpClient实现默认情况下无效,我们看看Apache HttpClient如何实现代理。
3.2 Apache HttpClient代理
3.2.1 为单个请求设置代理
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
= new HttpComponentsClientHttpRequestFactory(
HttpClientBuilder.create()
.setProxy(new HttpHost("10.145.9.74", 3128, "http"))
.build());
clientHttpRequestFactory.getHttpClient().execute(request);
3.2.2 根据URI选择代理服务器,也是使用ProxySelector
HttpRoutePlanner routePlanner = new SystemDefaultRoutePlanner(new MyProxySelector());
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
= new HttpComponentsClientHttpRequestFactory(
HttpClientBuilder.create()
.setRoutePlanner(routePlanner)
.build());
3.2.3 使用系统默认ProxySelector
HttpRoutePlanner routePlanner = new SystemDefaultRoutePlanner(ProxySelector.getDefault());
HttpClient httpClient = HttpClientBuilder
.create()
.setRoutePlanner(routePlanner)
.build();
- 3.2.2和3.2.3本质上是一样的,应用中同时存在HttpUrlConnection和Apache HttpClient两种实现,可以采用3.2.3来统一实现代理选择。
- Apache HttpClient 第三方库中如果没有提供指定代理的设置接口,只能修改代码了,没办法像HttpUrlConnection那样统一拦截。
网友评论