代理模式為其他對象提供一個代理以控制對這個對象的訪問。核心角色:
手動構造 HTTP 請求發送給代理服務器:
String proxyHost = "10.1.2.188";
int proxyPort = 80;
try (Socket socket = new Socket(proxyHost, proxyPort);
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream()) {
// 發送 HTTP 請求給代理,目標為百度
String request = "GET https://www.baidu.com/ HTTP/1.1\r\n" +
"Host: www.baidu.com\r\n" +
"Connection: close\r\n\r\n";
out.write(request.getBytes(StandardCharsets.UTF_8));
out.flush();
// 讀取響應
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) > 0) {
System.out.write(buffer, 0, len);
}
}
關鍵點:請求行必須包含完整目標 URL(GET https://target/ HTTP/1.1),並設置 Host 頭。
System.setProperty("http.proxyHost", "10.1.2.188");
System.setProperty("http.proxyPort", "80");
// HTTPS 代理
System.setProperty("https.proxyHost", "10.1.2.188");
System.setProperty("https.proxyPort", "443");
// 非代理主機
System.setProperty("http.nonProxyHosts", "localhost|192.168.*");
// 之後直接使用 URL.openConnection() 即可自動走代理
URL url = new URL("https://www.baidu.com");
try (InputStream in = url.openStream()) { /* 讀取 */ }
缺點:全局生效,無法針對單個連接單獨設置。
// HTTP 代理
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("192.168.0.254", 8080));
// SOCKS 代理
// Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("192.168.0.254", 1080));
URL url = new URL("https://www.baidu.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
// 設置認證
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("user", "pass".toCharArray());
}
});
try (InputStream in = conn.getInputStream()) { /* 讀取 */ }
優勢:每個連接可獨立設置代理類型、地址、認證,互不干擾。
SocketChannel sc = SocketChannel.open(new InetSocketAddress("10.1.2.188", 80));
sc.write(StandardCharsets.UTF_8.encode("GET https://www.baidu.com/ HTTP/1.1\r\n\r\n"));
ByteBuffer buf = ByteBuffer.allocate(1024);
while (sc.read(buf) != -1) {
buf.flip();
System.out.print(StandardCharsets.UTF_8.decode(buf));
buf.clear();
}
sc.close();
理解 HTTP/TCP 協議層級差異是正確使用網絡代理的前提。Socket 層面手動構造請求最靈活但繁瑣;URL/HttpURLConnection 配合 Proxy 類是 Java 應用層最推薦的方式。