Tomcat 中的 WEB 应用如何使用代理向外部发起请求


一直使用的阿里云ECS,经典网络类型。为什么不采用典型的专有网络 VPC 呢?因为考虑到成本嘛,而且也没有人来专门规划整个网络的,所以就采用最简单的经典网络,每台主机各自为政,都有自己的公网、私网出口,互不影响。

通过这种方式,发现有的服务器根本不需要外网带宽,比如负载均衡后面的服务器,因为负载均衡都是通过内网传输数据的,所以公网带宽完全就闲置起来了,而且暴露在公网中也比较危险。所以我们就开始购入没有公网IP的经典网络ECS。然后就遇到了下面的各种问题。

阿里云没有购买公网的情况下,不分配公网IP,也不能访问外网的资源,只能访问在同一个机房里面的服务器内网IP。这可怎么办呢?我们有些业务服务器是需要和外网进行交互的,比如进行资源加速的时候,是需要和CDN厂商服务器进行连接的,为了解决这个问题。我们在该机房中购买了一台公网带宽比较大的服务器,作为访问外网的代理服务器,安装了HTTP代理服务软件(记住哦,自己架设的代理服务器一定要设置密码,而且必须是强密码,不然一两天之类就会被整崩溃的。)

现在就开始把以前老的应用程序迁移到这台只有内网访问权限的服务器上,现在这台内网服务器上设置全局的HTTP代理信息,刚开始迁移PHP程序的时候,没任何问题,因为会自动根据系统的代理信息进行连接,但是Java web程序貌似走不通哎。现在重点讲 Java web如何使用代理程序进行连接。

前置条件:Tomcat VM 设置参数: 

-Dhttp.proxyHost=10.0.0.1 -Dhttp.proxyPort=1234

我分析了以下几种情况

  1. 使用jdk里面自带的库进行请求的时候,会自动根据VM参数进行连接。没有使用第三方库,详细代码参见:
 1  private static String sendGetByDefault(String url, String param) {
 2         String result = "";
 3         BufferedReader in = null;
 4         try {
 5             String urlNameString = url + "?" + param;
 6             URL realUrl = new URL(urlNameString);
 7             // 打开和URL之间的连接
 8             URLConnection connection = realUrl.openConnection();
 9             // 设置通用的请求属性
10             connection.setRequestProperty("accept", "*/*");
11             connection.setRequestProperty("connection", "Keep-Alive");
12             connection.setRequestProperty("user-agent",
13                     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
14             // 建立实际的连接
15             connection.connect();
16             // 获取所有响应头字段
17             Map<String, List<String>> map = connection.getHeaderFields();
18             // 遍历所有的响应头字段
19             for (String key : map.keySet()) {
20                 System.out.println(key + "--->" + map.get(key));
21             }
22             // 定义 BufferedReader输入流来读取URL的响应
23             in = new BufferedReader(new InputStreamReader(
24                     connection.getInputStream()));
25             String line;
26             while ((line = in.readLine()) != null) {
27                 result += line;
28             }
29         } catch (Exception e) {
30             System.out.println("发送GET请求出现异常!" + e);
31             e.printStackTrace();
32         }
33         // 使用finally块来关闭输入流
34         finally {
35             try {
36                 if (in != null) {
37                     in.close();
38                 }
39             } catch (Exception e2) {
40                 e2.printStackTrace();
41             }
42         }
43         return result;
44     }
View Code

   2. 使用Apache提供的第三方库,不会根据VM参数进行连接,maven信息参见:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.1</version>
</dependency>

   详细代码参见:

 private static String sendGetByApache(String url, String param) {
        StringBuilder buffer = new StringBuilder();

        DefaultHttpClient client = new DefaultHttpClient();
        try {
            HttpGet get = new HttpGet(url);
            HttpResponse response = client.execute(get);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                BufferedReader br = new BufferedReader(new InputStreamReader(entity.getContent()));
                String str;
                while ((str = br.readLine()) != null) {
                    buffer.append(str);
                }
                br.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client.getConnectionManager().shutdown();
        }

        return buffer.toString();
    }
View Code

  3. 使用Unirest库进行请求,不会根据VM代理信息进行连接,maven 信息参见:

<dependency>
    <groupId>com.mashape.unirest</groupId>
    <artifactId>unirest-java</artifactId>
    <version>1.4.7</version>
</dependency>     

   详细代码参见:

 private static String sendGetByUnirestClient(String url, String param) {
        com.mashape.unirest.http.HttpResponse<String> res;
        try {
            res = Unirest.get("http://baidu.com")
                    .queryString("name", "Mark")
                    .asString();
        } catch (UnirestException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        return res.getBody();
    }
View Code

  综上所述,基本上使用第三方库的都不会自动使用系统代理,所以我们要对程序进行一下改造。我们建议使用Unirest,因为他提供多种语言的HTTP请求库,并且风格一致,有利于不同语言之间的协作。

另外,如果在代码中采用硬编码的方式,代码如下:

 final String authUser = "proxy username";
final String authPassword = "proxy password";

Authenticator.setDefault(
                new Authenticator() {
                    @Override
                    public PasswordAuthentication getPasswordAuthentication() {
                        return new PasswordAuthentication(
                                authUser, authPassword.toCharArray());
                    }
                }
);
System.setProperty("http.proxyHost", "proxy host");
System.setProperty("http.proxyPort", "proxy password");
View Code

 

通过以上方式,可以使1,3两种情况自动通过代理进行连接,2依然我行我素。所以在公司内部统一使用某种库是非常有必要的。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM