为使用 HttpClient、Jsoup 和 Selenium 的 Java 应用配置代理,需要设置代理主机和端口——既可以通过 Java 系统属性进行全局配置,也可以针对各个库的连接对象单独配置,通常还需要包含身份验证的处理方式。
Java 中的代理基础
代理服务器充当网络请求的中间人,可带来更高的安全性、匿名性以及访问受地域限制内容的能力。在 Java 中,代理配置既可以在整个 Java 虚拟机(JVM)范围内生效,也可以只作用于单个 HTTP 客户端。
代理类型
- HTTP 代理: 处理 HTTP 请求(
http://)。 - HTTPS 代理: 处理 HTTPS 请求(
https://)。HTTP 代理通常也可以通过CONNECT方法处理 HTTPS 请求。 - SOCKS 代理: 支持多种网络协议,不限于 HTTP/HTTPS。灵活性更高,可处理 TCP 和 UDP 流量。
代理身份验证
许多代理需要身份验证(用户名/密码)。具体处理方式取决于代理是全局配置还是按客户端配置。
全局代理配置(Java 系统属性)
Java 提供了一组系统属性,用于配置对所有 java.net 连接生效的代理,其中包括由 HttpURLConnection(Jsoup 内部使用)发起的连接,以及默认沿用这些系统设置的其他库。
// 设置 HTTP 代理
System.setProperty("http.proxyHost", "proxy.example.com");
System.setProperty("http.proxyPort", "8080");
// 设置 HTTPS 代理(可与 HTTP 相同,也可不同)
System.setProperty("https.proxyHost", "proxy.example.com");
System.setProperty("https.proxyPort", "8080");
// 设置 SOCKS 代理
System.setProperty("socksProxyHost", "socks.example.com");
System.setProperty("socksProxyPort", "1080");
// 排除不走代理的主机(以逗号分隔的列表,允许使用通配符)
System.setProperty("http.nonProxyHosts", "localhost|127.0.0.1|*.local");
这些属性也可以作为 JVM 参数传入:
java -Dhttp.proxyHost=proxy.example.com -Dhttp.proxyPort=8080 YourApplication
全局代理的身份验证
对于需要身份验证的代理,可以使用 Java 的 Authenticator 类。它会为所有 java.net 连接设置一个默认的验证器。
import java.net.Authenticator;
import java.net.PasswordAuthentication;
public class GlobalProxyAuthenticator {
public static void setup(String username, String password) {
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// 检查该请求是否针对代理
if (getRequestorType() == RequestorType.PROXY) {
return new PasswordAuthentication(username, password.toCharArray());
}
return null; // 其他请求不进行身份验证
}
});
}
public static void main(String[] args) {
// 设置全局代理属性
System.setProperty("http.proxyHost", "authenticated-proxy.example.com");
System.setProperty("http.proxyPort", "8080");
System.setProperty("https.proxyHost", "authenticated-proxy.example.com");
System.setProperty("https.proxyPort", "8080");
// 配置验证器
GlobalProxyAuthenticator.setup("proxyuser", "proxypass");
// 此后,任何基于 HttpURLConnection 的请求都会尝试使用该代理和这组凭据
// 例如:Jsoup 会隐式使用它。
try {
org.jsoup.Connection.Response response = org.jsoup.Jsoup.connect("http://httpbin.org/get")
.ignoreContentType(true)
.execute();
System.out.println("Status: " + response.statusCode());
System.out.println("Body: " + response.body());
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
}
Apache HttpClient
Apache HttpClient 提供了健壮而灵活的 HTTP 请求方式,广泛用于复杂的集成场景。它支持按客户端实例显式配置代理。
HttpClient 4.x
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class HttpClient4ProxySetup {
public static void main(String[] args) throws Exception {
// 1. 定义代理主机
HttpHost proxy = new HttpHost("proxy.example.com", 8080, "http"); // 或 "https" 或 "socks"
// 2. 用代理配置请求
RequestConfig config = RequestConfig.custom()
.setProxy(proxy)
.build();
// 3.(可选)用于需要验证的代理:凭据提供器
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
new AuthScope(proxy.getHostName(), proxy.getPort()),
new UsernamePasswordCredentials("proxyuser", "proxypass"));
// 4. 构建 HttpClient
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultRequestConfig(config)
.setDefaultCredentialsProvider(credentialsProvider) // 用于需要验证的代理
.build();
// 5. 执行请求
HttpGet request = new HttpGet("http://httpbin.org/get");
request.setConfig(config); // 确保请求使用该配置
try (CloseableHttpResponse response = httpClient.execute(request)) {
System.out.println("Status: " + response.getStatusLine());
System.out.println("Body: " + EntityUtils.toString(response.getEntity()));
} finally {
httpClient.close();
}
}
}
HttpClient 5.x
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.ClassicHttpResponse;
public class HttpClient5ProxySetup {
public static void main(String[] args) throws Exception {
// 1. 定义代理主机
HttpHost proxy = new HttpHost("http", "proxy.example.com", 8080); // 协议、主机、端口
// 2.(可选)用于需要验证的代理:凭据提供器
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
new AuthScope(proxy.getHostName(), proxy.getPort()),
new UsernamePasswordCredentials("proxyuser", "proxypass".toCharArray()));
// 3. 构建 HttpClient
CloseableHttpClient httpClient = HttpClients.custom()
.setProxy(proxy) // 直接在客户端 builder 上设置代理
.setDefaultCredentialsProvider(credentialsProvider) // 用于需要验证的代理
.build();
// 4. 执行请求
HttpGet request = new HttpGet("http://httpbin.org/get");
// 如有需要,仍可用 RequestConfig 做单次请求级别的覆盖
RequestConfig requestConfig = RequestConfig.custom()
// .setProxy(proxy) // 也可在此设置单次请求使用的代理
.build();
request.setConfig(requestConfig);
try (CloseableHttpClient client = httpClient) {
client.execute(request, response -> {
System.out.println("Status: " + response.getCode());
System.out.println("Body: " + EntityUtils.toString(response.getEntity()));
return null;
});
}
}
}
Jsoup
Jsoup 是一个用于处理真实世界 HTML 的 Java 库,提供了抓取 URL 和解析 HTML 的简洁 API。Jsoup 的 Connection 接口允许直接配置代理。
import org.jsoup.Jsoup;
import org.jsoup.Connection;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
public class JsoupProxySetup {
public static void main(String[] args) {
String url = "http://httpbin.org/get";
String proxyHost = "proxy.example.com";
int proxyPort = 8080;
try {
// 方法 1:使用 proxy(host, port)
Connection.Response response1 = Jsoup.connect(url)
.proxy(proxyHost, proxyPort)
.ignoreContentType(true)
.execute();
System.out.println("Jsoup (Method 1) Status: " + response1.statusCode());
System.out.println("Jsoup (Method 1) Body: " + response1.body().substring(0, 100) + "...\n");
// 方法 2:使用 java.net.Proxy 对象
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
Connection.Response response2 = Jsoup.connect(url)
.proxy(proxy)
.ignoreContentType(true)
.execute();
System.out.println("Jsoup (Method 2) Status: " + response2.statusCode());
System.out.println("Jsoup (Method 2) Body: " + response2.body().substring(0, 100) + "...\n");
} catch (IOException e) {
System.err.println("Error connecting via Jsoup proxy: " + e.getMessage());
e.printStackTrace();
}
// 对于需要验证的代理,Jsoup 依赖 Java 全局系统属性和 Authenticator。
// 详见“全局代理配置”一节。
}
}
在 Jsoup 中使用需要验证的代理时,推荐的做法是按照“全局代理配置”一节所示,配置 Java 全局系统属性和 java.net.Authenticator。Jsoup 内部的 HttpURLConnection 会自动读取这些设置。
Selenium WebDriver
Selenium 用于自动化 Web 浏览器。Selenium WebDriver 的代理配置通常通过各浏览器专属的选项完成。
Chrome WebDriver
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
public class SeleniumChromeProxySetup {
public static void main(String[] args) {
// 设置 ChromeDriver 可执行文件的路径
// System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
String proxyHost = "proxy.example.com";
int proxyPort = 8080;
String proxyAddress = proxyHost + ":" + proxyPort;
Proxy proxy = new Proxy();
proxy.setHttpProxy(proxyAddress); // 用于 HTTP 流量
proxy.setSslProxy(proxyAddress); // 用于 HTTPS 流量(通常与 HTTP 相同)
proxy.setSocksProxy(proxyAddress); // 用于 SOCKS 流量
// proxy.setSocksUsername("socksuser"); // 用于 SOCKS5 身份验证
// proxy.setSocksPassword("sockspass");
ChromeOptions options = new ChromeOptions();
options.setCapability("proxy", proxy);
// options.addArguments("--proxy-server=" + proxyAddress); // 简单 HTTP/HTTPS 代理的替代写法
WebDriver driver = new ChromeDriver(options);
try {
driver.get("http://httpbin.org/get");
System.out.println("Page title: " + driver.getTitle());
// 后续与页面的交互……
} finally {
driver.quit();
}
}
}
Firefox WebDriver
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
public class SeleniumFirefoxProxySetup {
public static void main(String[] args) {
// 设置 GeckoDriver 可执行文件的路径
// System.setProperty("webdriver.gecko.driver", "/path/to/geckodriver");
String proxyHost = "proxy.example.com";
int proxyPort = 8080;
String proxyAddress = proxyHost + ":" + proxyPort;
Proxy proxy = new Proxy();
proxy.setHttpProxy(proxyAddress);
proxy.setSslProxy(proxyAddress);
proxy.setSocksProxy(proxyAddress);
// proxy.setSocksUsername("socksuser");
// proxy.setSocksPassword("sockspass");
FirefoxOptions options = new FirefoxOptions();
options.setCapability("proxy", proxy);
WebDriver driver = new FirefoxDriver(options);
try {
driver.get("http://httpbin.org/get");
System.out.println("Page title: " + driver.getTitle());
} finally {
driver.quit();
}
}
}
Selenium 中的代理身份验证
Selenium WebDriver 本身并不直接处理代理身份验证(HTTP/HTTPS 代理的用户名/密码)。常见做法包括:
- 浏览器扩展: 使用能够处理代理身份验证的浏览器扩展。这些扩展可通过
ChromeOptions或FirefoxOptions加载。 - URL 中携带代理凭据: 对部分 HTTP 代理,可以把凭据嵌入代理 URL(例如
user:[email protected]:8080),但这并非普遍支持,也不安全。 - SOCKS5 身份验证: Selenium 的
Proxy类为 SOCKS5 代理提供setSocksUsername()和setSocksPassword()。 - 上游代理服务器: 将流量转发到另一个本地代理服务器(例如 BrowserMob Proxy),由它负责与目标代理完成身份验证。
各种代理配置方式对比
| 特性 | Java 系统属性(-D) |
Apache HttpClient(4.x/5.x) | Jsoup(.proxy()) |
Selenium WebDriver(Proxy 类) |
|---|---|---|---|---|
| 作用范围 | 全局(整个 JVM) | 每个 HttpClient 实例 |
每个 Connection 实例 |
每个 WebDriver 实例 |
| 身份验证 | java.net.Authenticator(全局) |
CredentialsProvider(按客户端) |
java.net.Authenticator(若已全局配置) |
SOCKS5(setSocksUsername/Password);HTTP/HTTPS 通常靠扩展/外部工具 |
| 灵活性 | 低(影响所有 java.net 连接) |
高(可精细控制,支持按请求配置) | 中(按连接配置,但身份验证依赖全局设置) | 高(浏览器专属选项、SOCKS 验证) |
| 易用性 | 高(属性设置简单) | 中到高(需要更多代码) | 高(方法调用简单) | 中(需创建 Proxy 对象并设置选项) |
| 支持的协议 | HTTP、HTTPS、SOCKS | HTTP、HTTPS、SOCKS | HTTP、HTTPS(通过 HttpURLConnection) |
HTTP、HTTPS、SOCKS(取决于浏览器能力) |
| 适用场景 | 全应用统一、简单的代理需求 | 复杂 HTTP 交互、API 客户端 | Web scraping、简单页面抓取 | 浏览器自动化、测试、web scraping |
