首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 應用程式支援 Proxy 代理伺服器完整實作指南

     編輯:Java 相關知識

企業網路環境下的代理挑戰

企業防火牆通常封鎖直接外部連線,強制透過 HTTP/SOCKS Proxy 存取外網。Java 應用若不支援 Proxy,在企業環境將完全無法連線。幸運的是,Java 提供系統屬性與程式化 API 完整支援各類代理協定。

方案一:系統屬性啟動參數(最簡單、零程式碼修改)

HTTP/HTTPS Proxy

java -Dhttp.proxyHost=proxy.company.com \
     -Dhttp.proxyPort=8080 \
     -Dhttps.proxyHost=proxy.company.com \
     -Dhttps.proxyPort=8080 \
     -Dhttp.nonProxyHosts="localhost|127.0.0.1|*.internal.com" \
     -jar myapp.jar
  • http.nonProxyHosts:繞過代理的主機清單,支援萬用字元 | 分隔。
  • JVM 內建 HttpURLConnection、HttpsURLConnection 自動讀取這些屬性。

SOCKS 4/5 Proxy

java -DsocksProxyHost=proxy.company.com \
     -DsocksProxyPort=1080 \
     -DsocksProxyVersion=5 \  # 預設 5,支援 4
     -jar myapp.jar
  • 適用於 Socket、DatagramSocket、RMI、JDBC 等 TCP 連線。
  • SOCKS 5 支援 UDP 與驗證,SOCKS 4 僅 TCP。

驗證機制(Basic Auth)

系統屬性**不支援**直接指定帳密。需在程式碼設定 Authenticator:

import java.net.*;

public class ProxyAuthSetup {
    public static void setup(String username, String password) {
        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password.toCharArray());
            }
        });
    }
}
// 主程式啟動時呼叫
ProxyAuthSetup.setup("proxyUser", "proxyPass");

方案二:程式化 Proxy 選擇器(精細控制每個連線)

import java.net.*;

public class ProxySelectorExample {
    public static void main(String[] args) throws Exception {
        // 1. 定義代理
        Proxy httpProxy = new Proxy(Proxy.Type.HTTP,
            new InetSocketAddress("proxy.company.com", 8080));

        Proxy socksProxy = new Proxy(Proxy.Type.SOCKS,
            new InetSocketAddress("socks.company.com", 1080));

        Proxy noProxy = Proxy.NO_PROXY; // 直連

        // 2. 建立連線時指定 Proxy
        URL url = new URL("https://api.external.com/data");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection(httpProxy);

        // 3. 設定驗證(若該 Proxy 需要)
        String auth = "user:pass";
        String encoded = Base64.getEncoder().encodeToString(auth.getBytes());
        conn.setRequestProperty("Proxy-Authorization", "Basic " + encoded);

        // 4. 正常使用
        try (InputStream is = conn.getInputStream()) {
            // 處理回應...
        }
    }
}

方案三:全域 ProxySelector(動態路由規則)

import java.net.*;
import java.util.*;

public class CustomProxySelector extends ProxySelector {
    private final ProxySelector defaultSelector;

    public CustomProxySelector() {
        this.defaultSelector = ProxySelector.getDefault();
    }

    @Override
    public List select(URI uri) {
        String host = uri.getHost();
        // 內網直連
        if (host.endsWith(".internal.com") || host.equals("localhost")) {
            return Collections.singletonList(Proxy.NO_PROXY);
        }
        // 外網走 HTTP Proxy
        return Collections.singletonList(
            new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.company.com", 8080))
        );
    }

    @Override
    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
        // 失敗轉向預設選擇器
        defaultSelector.connectFailed(uri, sa, ioe);
    }
}

// 啟動時註冊
ProxySelector.setDefault(new CustomProxySelector());

常見協定與代理對應表

協定/APIHTTP ProxyHTTPS ProxySOCKS Proxy備註
HttpURLConnection✅ 自動✅ 自動 (CONNECT 隧道)✅ 程式化指定最常用
HttpsURLConnection✅ 自動✅ 自動✅ 程式化指定SSL 握手在隧道內
Socket / ServerSocket❌❌✅ 系統屬性/程式化需 SOCKS
RMI / JMX❌❌✅ -DsocksProxyHost建議用 SOCKS
JDBC (資料庫驅動)視驅動而定視驅動而定視驅動而定多數支援 SOCKS 或自有 Proxy 參數
FTP (URL "ftp://")✅ ftp.proxyHost❌❌舊 API,建議改用 Apache Commons Net

避坑指南與最佳實踐

  1. HTTPS 透過 HTTP Proxy:瀏覽器發送 CONNECT host:443 HTTP/1.1 建立 TLS 隧道,Java 自動處理,**無法攔截解密內容**(除非中間人憑證)。
  2. Proxy-Authorization 標頭格式:Basic base64(user:pass),注意 Basic 關鍵字與 base64 之間有空格。
  3. 非標準埠口:http.proxyPort 預設 80,https.proxyPort 預設 443,企業 Proxy 常用 8080、3128、8888,**必須明確指定**。
  4. Docker 容器內:容器網路隔離,宿主機 Proxy 不自動透傳。需在 Dockerfile 或 docker run -e 傳入 HTTP_PROXY/HTTPS_PROXY 環境變數,啟動腳本轉為 -D 參數。
  5. 測試連通性:telnet proxy.company.com 8080 或 curl -x proxy.company.com:8080 https://httpbin.org/ip 確認 Proxy 本身可達。

程式碼片段:通用 Proxy 工具類

public final class ProxyUtils {
    private ProxyUtils() {}

    public static HttpURLConnection openConnection(URL url, ProxyConfig config) throws IOException {
        Proxy proxy = config.toProxy();
        HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
        if (config.requiresAuth()) {
            String auth = config.getUsername() + ":" + config.getPassword();
            String encoded = Base64.getEncoder().encodeToString(auth.getBytes());
            conn.setRequestProperty("Proxy-Authorization", "Basic " + encoded);
        }
        return conn;
    }

    public static class ProxyConfig {
        private final Proxy.Type type;
        private final String host;
        private final int port;
        private final String username;
        private final String password;

        public ProxyConfig(Proxy.Type type, String host, int port) {
            this(type, host, port, null, null);
        }
        public ProxyConfig(Proxy.Type type, String host, int port, String username, String password) {
            this.type = type; this.host = host; this.port = port;
            this.username = username; this.password = password;
        }
        public Proxy toProxy() {
            return new Proxy(type, new InetSocketAddress(host, port));
        }
        public boolean requiresAuth() { return username != null && password != null; }
        public String getUsername() { return username; }
        public String getPassword() { return password; }
    }
}

總結:簡單部署用 -Dhttp.proxyHost 啟動參數;需動態切換、多代理路由用 ProxySelector;精細控制單一連線用 url.openConnection(proxy)。驗證統一用 Authenticator 或手動加 Proxy-Authorization 標頭。記得處理 http.nonProxyHosts 避免內網流量繞道。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved