Java 11开始提供标准的java.net.http.HttpClient,可以用于发送HTTP和HTTPS请求。
如果业务需要通过固定代理或长效代理访问公开接口,可以直接通过ProxySelector配置代理服务器。
本文演示:
Java HttpClient配置代理;
设置连接和请求超时;
处理代理认证;
判断常见异常;
复用HttpClient连接。
携趣官方长效代理提供固定IP和端口,支持HTTP(S)和S5协议,可直接配置在浏览器、软件或代码中。
一、配置不带账号密码的HTTP代理
import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class HttpProxyDemo {
public static void main(String[] args) throws Exception {
String proxyHost = "127.0.0.1";
int proxyPort = 8080;
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.proxy(
ProxySelector.of(
new InetSocketAddress(
proxyHost,
proxyPort
)
)
)
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/ip"))
.timeout(Duration.ofSeconds(20))
.header(
"User-Agent",
"Java-Proxy-Test/1.0"
)
.GET()
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.statusCode());
System.out.println(response.body());
}
}
二、配置代理账号和密码
如果代理使用账号密码认证,可以配置Authenticator:
import java.net.Authenticator;
import java.net.PasswordAuthentication;
Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication
getPasswordAuthentication() {
return new PasswordAuthentication(
"proxyUsername",
"proxyPassword".toCharArray()
);
}
};
完整构建方式:
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.proxy(
ProxySelector.of(
new InetSocketAddress(
proxyHost,
proxyPort
)
)
)
.authenticator(authenticator)
.build();
需要注意,不要将真实账号密码直接提交到Git仓库。
可以通过环境变量读取:
String username = System.getenv("PROXY_USERNAME");
String password = System.getenv("PROXY_PASSWORD");
三、白名单认证和账号密码认证怎么选?
常见代理认证方式包括:
公网IP白名单;
用户名和密码;
两者组合。
白名单方式适合公网IP固定的服务器。
如果运行环境是家庭宽带或者动态公网IP,白名单可能随公网IP变化而失效。携趣官方提供白名单管理和自动同步工具,用于处理动态公网IP变化导致的授权失效问题。
四、增加异常处理
import java.io.IOException;
import java.net.ConnectException;
import java.net.http.HttpConnectTimeoutException;
import java.net.http.HttpTimeoutException;
public class ProxyRequestService {
private final HttpClient client;
public ProxyRequestService(
String proxyHost,
int proxyPort
) {
this.client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.proxy(
ProxySelector.of(
new InetSocketAddress(
proxyHost,
proxyPort
)
)
)
.build();
}
public String get(String url)
throws InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofSeconds(20))
.GET()
.build();
try {
HttpResponse<String> response =
client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() == 407) {
throw new IllegalStateException(
"代理认证失败"
);
}
if (response.statusCode() >= 500) {
throw new IllegalStateException(
"服务端异常: "
+ response.statusCode()
);
}
return response.body();
} catch (HttpConnectTimeoutException e) {
throw new IllegalStateException(
"连接代理服务器超时",
e
);
} catch (HttpTimeoutException e) {
throw new IllegalStateException(
"请求响应超时",
e
);
} catch (ConnectException e) {
throw new IllegalStateException(
"无法连接代理服务器",
e
);
} catch (IOException e) {
throw new IllegalStateException(
"网络请求失败",
e
);
}
}
}
五、不要为每个请求创建一个HttpClient
不推荐:
for (...) {
HttpClient client = HttpClient.newBuilder()
.proxy(...)
.build();
client.send(...);
}
更合理的方式是复用HttpClient实例。
原因包括:
可以减少重复创建对象;
有利于复用底层连接;
配置统一;
更容易集中处理超时和认证;
便于后续增加日志和监控。
六、固定代理和动态代理的代码差异
固定代理:
创建HttpClient → 连续发送请求
短效动态代理:
调用代理API → 创建或更新代理配置 → 发送请求
Java标准HttpClient构建后,其代理选择器通常不会频繁变化。
如果需要高频切换代理,可以:
为每个代理维护一个HttpClient;
自定义动态ProxySelector;
使用Apache HttpClient;
使用固定入口的隧道代理。
总结
Java 11 HttpClient接入固定代理的关键步骤包括:
使用ProxySelector配置代理;
设置连接超时和请求超时;
根据需要配置认证;
识别407等代理相关状态;
复用HttpClient;
不在代码中暴露账号密码。
对于需要稳定固定出口的Java服务,可以使用长效代理;对于高频自动轮换需求,则应考虑动态代理管理或固定入口的隧道代理。