企業網路環境普遍部署代理伺服器以管控對外存取。Java 應用若需通過代理訪問外部資源,需正確配置系統屬性與認證機制。本文詳解 HTTP/HTTPS、FTP、SOCKS 代理配置細節、認證處理與常見坑點。
JVM 透過 System.setProperty() 或啟動參數 -D 設定代理屬性,必須在建立網路連線前配置。
// 基礎配置
System.setProperty("http.proxySet", "true");
System.setProperty("http.proxyHost", "proxy.example.com");
System.setProperty("http.proxyPort", "8080");
System.setProperty("https.proxyHost", "proxy.example.com");
System.setProperty("https.proxyPort", "8080");
// 非代理主機清單(支援萬用字元)
System.setProperty("http.nonProxyHosts", "localhost|127.0.0.1|*.internal.com");
System.setProperty("ftp.proxySet", "true");
System.setProperty("ftp.proxyHost", "proxy.example.com");
System.setProperty("ftp.proxyPort", "2121");
System.setProperty("socksProxySet", "true");
System.setProperty("socksProxyHost", "proxy.example.com");
System.setProperty("socksProxyPort", "1080"); // SOCKS 預設 1080
// JDK 1.5+ 支援 SOCKS5 驗證
System.setProperty("java.net.socks.username", "user");
System.setProperty("java.net.socks.password", "pass");
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("username", "password".toCharArray());
}
});
適用於 HTTP/HTTPS/FTP/SOCKS 統一認證,程式碼無侵入性。
URL url = new URL("https://target.com/resource");
URLConnection conn = url.openConnection();
String auth = "username:password";
String encoded = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
conn.setRequestProperty("Proxy-Authorization", "Basic " + encoded);
注意:Header 值必須包含 "Basic " 前綴,且使用標準 Base64 編碼(JDK 8+ 使用 java.util.Base64,避免使用內部類 sun.misc.BASE64Encoder)。
HTTP、HTTPS、FTP 可分別設定不同代理主機/埠,互不干擾。
系統屬性為 JVM 全域生效,若需執行緒級別隔離,需自行實現 ProxySelector 或使用 Apache HttpClient 等支援細粒度代理控制的庫。
new URL(protocol, host, port, file) 建構子指定代理sun.misc.BASE64Encoder,改用 java.util.Base64HttpClient.newBuilder().proxy(ProxySelector.of(...)))http.nonProxyHosts 支援 | 分隔、* 萬用字元,不支援 CIDR 表示法。主機名匹配不區分大小寫。
預設情況下 JVM 會嘗試對本地位址走代理,建議明確加入:
System.setProperty("http.nonProxyHosts", "localhost|127.0.0.1|::1");
public class ProxyConfig {
public static void configure(HttpProxyConfig config) {
// HTTP/HTTPS
setProxy("http", config.getHost(), config.getPort());
setProxy("https", config.getHost(), config.getPort());
// 非代理清單
if (config.getNonProxyHosts() != null) {
System.setProperty("http.nonProxyHosts", config.getNonProxyHosts());
}
// 認證
if (config.requiresAuth()) {
Authenticator.setDefault(new ProxyAuthenticator(config.getUser(), config.getPassword()));
}
}
private static void setProxy(String protocol, String host, int port) {
System.setProperty(protocol + ".proxySet", "true");
System.setProperty(protocol + ".proxyHost", host);
System.setProperty(protocol + ".proxyPort", String.valueOf(port));
}
}
// 簡單測試
URL url = new URL("https://httpbin.org/ip");
try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()))) {
System.out.println("代理生效,回應 IP: " + in.readLine());
}
回應 IP 應為代理伺服器出口 IP,而非本機公網 IP。
Java 代理配置核心在於早期設定系統屬性與正確處理認證 Header。現代專案建議採用 Apache HttpClient、OkHttp 或 JDK 11+ HttpClient,享受更靈活的代理控制、連線池管理與非同步支援。排查代理問題時,優先檢查:屬性拼寫、設定時機、認證格式、非代理清單、防火牆/代理伺服器端日誌。