Java HttpClient with AeonProxy proxies
Point java.net.http.HttpClient at port 7000 with a ProxySelector, allow Basic auth for HTTPS tunnels, and log in with an Authenticator or a header.
- Protocols
- HTTP proxy in
HttpClient; SOCKS5 only inHttpURLConnection - Authentication
- Login and password through an
Authenticatoror aProxy-Authorizationheader - Rotation
- A new IP per connection (a client pools its connections); a
-sid-key keeps one IP for up to 60 minutes - Works with
- Residential and mobile proxies
Before you start
- Java 11 or newer; the sessions example needs Java 21, where
HttpClientcan be closed. Run a file withjava ProxyExample.java, no build step. - Your proxy login and password from the Residential or Mobile page of the dashboard, and traffic on that product; without traffic every request gets 402.
- Host
gate.aeonproxy.com- Port (HTTP / HTTPS)
7000- Port (SOCKS5)
7001- Login
- your proxy login, with targeting keys if you need them:
LOGIN-cc-us-sid-abc123 - Password
- your proxy password
Copy the login and password from the Residential or Mobile page of the dashboard; the generator there also writes ready lines. Key syntax: targeting and sessions.
Allow Basic auth for HTTPS tunnels
The JDK's conf/net.properties sets jdk.http.auth.tunneling.disabledSchemes=Basic, so Java sends no login on the CONNECT request that opens an HTTPS tunnel, and every HTTPS request through the gateway ends with status 407, even with the right password. Clear the list on the command line:
java -Djdk.http.auth.tunneling.disabledSchemes= ProxyExample.javaor with System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "") before the first client is built: Java reads the setting only once. http:// sites are not affected.
HttpClient with a ProxySelector and an Authenticator
ProxySelector.of points the client at port 7000. Its first CONNECT goes out without a login; after the gateway's 407 the client asks the Authenticator, repeats the request with the login, and sends the login up front on its later connections. Answer only for requestor type PROXY, so websites never get the password.
import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
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 ProxyExample {
public static void main(String[] args) throws Exception {
// Basic auth for HTTPS tunnels is off by default: allow it before the first client is built
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
HttpClient client = HttpClient.newBuilder()
.proxy(ProxySelector.of(new InetSocketAddress("gate.aeonproxy.com", 7000)))
.authenticator(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType() != RequestorType.PROXY) return null; // never send it to websites
return new PasswordAuthentication("LOGIN-cc-us", "PASSWORD".toCharArray());
}
})
.connectTimeout(Duration.ofSeconds(30))
.build();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.ipify.org"))
.timeout(Duration.ofSeconds(30)).build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.statusCode() + " " + res.body());
}
}Rotating or sticky
A client pools its connections, so its requests usually share an IP. With a rotating login, a new client per request gets a new IP each time; with a -sid- key, every connection keeps the same IP until the -ttl- runs out (1 to 60 minutes).
Each new client sends its first CONNECT without a login and repeats it with the login after the gateway's 407, one extra round trip per client; the gateway does not count that first try as a failed login. When you open a new client per request, send the login up front in a Proxy-Authorization header, as this example does. Java puts it on the CONNECT request only, never on the request to the site.
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;
import java.util.Base64;
public class Sessions {
static String exitIp(String login) throws Exception {
String auth = "Basic " + Base64.getEncoder().encodeToString((login + ":PASSWORD").getBytes());
HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.ipify.org"))
.header("Proxy-Authorization", auth) // goes with the CONNECT only, never to the site
.timeout(Duration.ofSeconds(30))
.build();
try (HttpClient client = HttpClient.newBuilder() // a new client opens a new connection
.proxy(ProxySelector.of(new InetSocketAddress("gate.aeonproxy.com", 7000)))
.build()) {
return client.send(req, HttpResponse.BodyHandlers.ofString()).body();
}
}
public static void main(String[] args) throws Exception {
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
System.out.println(exitIp("LOGIN-cc-us") + " " + exitIp("LOGIN-cc-us")); // two IPs
String sticky = "LOGIN-cc-us-sid-ab12cd34-ttl-30";
System.out.println(exitIp(sticky) + " " + exitIp(sticky)); // one IP for up to 30 minutes
}
}SOCKS5: HttpURLConnection only
HttpClient ignores SOCKS proxies: given Proxy.Type.SOCKS, it connects directly, from your own IP, without an error.
HttpURLConnection supports SOCKS5 and asks the default Authenticator for the login, with the protocol SOCKS5. It resolves the site's name on your machine, so the DNS lookup leaves from your own network.
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URI;
public class SocksExample {
public static void main(String[] args) throws Exception {
// the SOCKS5 login comes from the default Authenticator
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (!"SOCKS5".equals(getRequestingProtocol())) return null;
return new PasswordAuthentication("LOGIN-cc-de", "PASSWORD".toCharArray());
}
});
Proxy socks = new Proxy(Proxy.Type.SOCKS, InetSocketAddress.createUnresolved("gate.aeonproxy.com", 7001));
HttpURLConnection conn = (HttpURLConnection) URI.create("https://api.ipify.org").toURL().openConnection(socks);
conn.setConnectTimeout(30_000);
conn.setReadTimeout(30_000);
try (var in = conn.getInputStream()) {
System.out.println(new String(in.readAllBytes()));
}
}
}If it does not work
| What you see | What to check |
|---|---|
| Status 407 with the right password | Basic is still disabled for tunnels. Clear jdk.http.auth.tunneling.disabledSchemes before the first client is built. |
IOException: too many authentication attempts. Limit: 3 | The login, the password, or a key that is not in the lists (a misspelled city, for example). |
IOException: Tunnel failed, got: 402 or 502 | 402: no traffic left on the product, or the sub-user reached its limit. 502: the exit failed; retry. |
Tunnel failed, got: 429 | 30 failed logins in a minute from your address: a wrong password or key, repeated by many threads. Java retries a wrong password, so each one counts several times. Fix the login and wait a minute. |
| Your own IP instead of the proxy's | A SOCKS proxy in the ProxySelector, which HttpClient ignores. Use port 7000. |
Questions
Yes. A client built without .proxy(...) uses the default ProxySelector, which reads https.proxyHost and https.proxyPort (http. for http:// sites). The login still comes from an Authenticator or the header.
Yes: openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("gate.aeonproxy.com", 7000))) with a default Authenticator that answers for RequestorType.PROXY, and the same Basic setting cleared for HTTPS sites.