Java原生HttpClient通过带Basic认证代理访问HTTPS资源问题
解决方案
可以通过Java 16内置的HttpClient实现带Basic认证的HTTP代理访问HTTPS资源,你之前的代码存在两处错误导致HTTPS场景返回407状态码:
- 构造
InetSocketAddress时传入了带http://前缀的代理地址,该类仅需要填写纯主机名,不需要scheme前缀 - 自定义
Authenticator没有判断请求类型为代理认证,导致HTTPS隧道建立的CONNECT请求阶段没有携带代理凭证
修正后完整可运行代码
import java.net.*; import java.net.http.*; import java.time.Duration; // 原有ProxySettings定义无需修改 public record ProxySettings(String scheme, String hostname, int port, String userName, String password) { public char[] getPasswordArray() { return password.toCharArray(); } public String getUri() { return scheme + "://" + hostname; } } public class ProxyHttpsTest { public static void main(String[] args) throws Exception { // 替换为实际代理参数 ProxySettings proxySettings = new ProxySettings("http", "proxy.ip.address", 8080, "userName", "password"); HttpRequest request = HttpRequest.newBuilder(new URI("https://yandex.ru")).build(); HttpClient client = HttpClient.newBuilder() // 修正1:仅传入代理主机名和端口构造InetSocketAddress .proxy(ProxySelector.of(new InetSocketAddress(proxySettings.hostname(), proxySettings.port()))) // 修正2:仅在代理认证请求时返回凭证 .authenticator(new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { if (getRequestorType() == RequestorType.PROXY) { return new PasswordAuthentication(proxySettings.userName(), proxySettings.getPasswordArray()); } return super.getPasswordAuthentication(); } }) .connectTimeout(Duration.ofSeconds(10)) .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("响应状态码:" + response.statusCode()); System.out.println("响应体:" + response.body()); } }
兼容备用方案
如果部分特殊代理对上述Authenticator逻辑兼容性不佳,可手动构造代理认证头实现,无需配置Authenticator:
import java.net.*; import java.net.http.*; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.time.Duration; // 构造认证头 String authStr = proxySettings.userName() + ":" + proxySettings.password(); String encodedAuth = Base64.getEncoder().encodeToString(authStr.getBytes(StandardCharsets.UTF_8)); HttpRequest request = HttpRequest.newBuilder(new URI("https://yandex.ru")) .header("Proxy-Authorization", "Basic " + encodedAuth) .build(); // 客户端无需配置authenticator HttpClient client = HttpClient.newBuilder() .proxy(ProxySelector.of(new InetSocketAddress(proxySettings.hostname(), proxySettings.port()))) .connectTimeout(Duration.ofSeconds(10)) .build();
内容的提问来源于stack exchange,提问作者Leonis
相关产品推荐
相关产品推荐

