java代碼實現代理服務器不建議用來翻牆

 

注:本文來自風馬博客

需求描述

    在正常的項目開發需求中,連接遠程服務器的場景一般有二:

    1  自家實現的http服務器,api接口都已經約定好;

    2  開發平臺服務,通常如新浪、百度雲等平臺提供的restful接口;

 

    以上的兩種場景通過原生的URLConnection或是apache提供的httpclient工具包都可以方便的實現調用。

 

    然而,第三種場景是需要連接國外的開放服務,如google、twitter、tumblr等開放API接口。

    在偉大的gfw關懷下,我們被告知不要隨便和陌生人說話...

    好吧,接下來讓我們開始實現基於proxy的穿越吧!

 

準備工作

    1  http代理服務器

        建議花點銀子買個穩定的VPN,帶http代理的那種。

 

    2  外網訪問測試

        可以用chrome switchyOmega插件測試一把,不行直接設置IE系統代理

 

    準備完畢,可以開始開發了。

    注:本文來自風馬博客

 

java代碼實現代理服務器不建議用來翻牆,不支持vpn.

設計分析

代理連接實現的關鍵步驟:

    一、設置代理服務器地址端口

           方式一: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的方式則不需要動裏面的代碼,綠色輕便。java代碼實現代理服務器不建議用來翻牆,不支持vpn.

 

    二、實現用戶密碼校驗

     方式一:將校驗信息寫入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);

java代碼實現代理服務器不建議用來翻牆,不支持vpn。注:本文來自風馬博客

 

實例代碼

入口類

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());

    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章