Les applications Java d'entreprise accèdent régulièrement à des API externes, analysent des données ou fonctionnent dans des réseaux d'entreprise isolés — et dans chacun de ces cas, tôt ou tard, la question de la routage du trafic via un serveur proxy se pose. Configurer un proxy en Java semble être une tâche simple, jusqu'à ce que l'on se rende compte que RestTemplate, OkHttp et WebClient se comportent différemment, et que les propriétés système de la JVM ne fonctionnent pas partout. Dans ce guide, vous trouverez des exemples de code concrets, des explications sur les pièges à éviter et des recommandations sur le choix du type de proxy pour différentes tâches.
Pourquoi les applications Java ont besoin de proxies
Java reste l'un des principaux langages de développement d'entreprise. Les services Spring Boot, les architectures microservices, les tâches batch, les pipelines ETL — tout cela effectue régulièrement des requêtes HTTP vers le monde extérieur. Et dans chacun de ces scénarios, un proxy résout une tâche spécifique :
- Réseaux d'entreprise avec un proxy obligatoire. Dans de nombreuses entreprises, tout le trafic sortant passe par un proxy d'entreprise (Squid, Zscaler, BlueCoat). Sans sa configuration, l'application ne pourra tout simplement pas accéder à Internet.
- Analyse et collecte de données. Les services qui collectent des données à partir de sites externes (prix, cotations, actualités) utilisent des proxies pour contourner les limites de fréquence et les blocages par IP.
- Tests géographiques. Les équipes QA vérifient comment l'API ou le site se comporte depuis différentes régions — un proxy permet d'émuler une requête depuis le pays souhaité.
- Contourner les restrictions du côté de l'API cible. Certaines API externes ont des limites sur le nombre de requêtes provenant d'une seule IP. La rotation des proxies permet de répartir la charge.
- Sécurité et anonymisation. Cacher l'IP réelle de l'application lors de l'accès à des services externes est une pratique standard pour les intégrations sensibles.
Selon la tâche, les approches pour configurer un proxy en Java varient considérablement. Les propriétés système globales de la JVM sont l'option la plus simple, mais elles ne fonctionnent pas avec certains clients HTTP. OkHttp et WebClient nécessitent une configuration explicite. Examinons chaque cas en détail.
Configuration globale via les propriétés système de la JVM
Le moyen le plus rapide de diriger tout le trafic HTTP d'une application Java à travers un proxy est d'utiliser les propriétés système de la JVM. Cela fonctionne pour le HttpURLConnection standard et de nombreuses bibliothèques qui l'utilisent en arrière-plan.
Vous pouvez définir un proxy de plusieurs manières :
1. Via les arguments de la JVM lors du démarrage :
java -Dhttp.proxyHost=proxy.example.com \
-Dhttp.proxyPort=8080 \
-Dhttps.proxyHost=proxy.example.com \
-Dhttps.proxyPort=8080 \
-Dhttp.nonProxyHosts="localhost|127.0.0.1|*.internal.corp" \
-jar myapp.jar
2. Via le code de l'application (par exemple, dans la méthode main ou dans @PostConstruct) :
System.setProperty("http.proxyHost", "proxy.example.com");
System.setProperty("http.proxyPort", "8080");
System.setProperty("https.proxyHost", "proxy.example.com");
System.setProperty("https.proxyPort", "8080");
// Exclusions — hôtes qui ne doivent pas passer par le proxy
System.setProperty("http.nonProxyHosts", "localhost|127.0.0.1|*.internal.corp");
3. Via le fichier application.properties dans Spring Boot (avec application ultérieure via @PostConstruct) :
# application.properties proxy.host=proxy.example.com proxy.port=8080 proxy.username=user proxy.password=secret
⚠️ Important à savoir
Les propriétés système de la JVM ne fonctionnent que pour HttpURLConnection. OkHttp, Apache HttpClient et Reactor Netty (WebClient) ignorent ces propriétés — ils nécessitent une configuration explicite, décrite ci-dessous.
Si le proxy nécessite une authentification, utilisez Authenticator :
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType() == RequestorType.PROXY) {
return new PasswordAuthentication("username", "password".toCharArray());
}
return null;
}
});
Proxy dans Spring Boot : RestTemplate et Apache HttpClient
RestTemplate est le client HTTP synchrone standard dans Spring. Par défaut, il utilise SimpleClientHttpRequestFactory, qui repose sur HttpURLConnection et lit les propriétés système de la JVM. Mais pour une configuration plus flexible (timeouts, pool de connexions, proxy avec authentification), il est recommandé d'utiliser Apache HttpClient comme backend.
Dépendance dans Maven :
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version>
</dependency>
Configuration de RestTemplate avec un proxy via Apache HttpClient 5 :
@Configuration
public class RestTemplateConfig {
@Value("${proxy.host}")
private String proxyHost;
@Value("${proxy.port}")
private int proxyPort;
@Value("${proxy.username:}")
private String proxyUsername;
@Value("${proxy.password:}")
private String proxyPassword;
@Bean
public RestTemplate restTemplate() {
HttpHost proxy = new HttpHost("http", proxyHost, proxyPort);
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
if (!proxyUsername.isEmpty()) {
credentialsProvider.setCredentials(
new AuthScope(proxyHost, proxyPort),
new UsernamePasswordCredentials(proxyUsername, proxyPassword.toCharArray())
);
}
CloseableHttpClient httpClient = HttpClients.custom()
.setProxy(proxy)
.setDefaultCredentialsProvider(credentialsProvider)
.build();
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setConnectTimeout(5000);
factory.setReadTimeout(10000);
return new RestTemplate(factory);
}
}
Cette configuration permet de sortir les paramètres du proxy dans application.properties ou des variables d'environnement, ce qui est critique pour les environnements prod/staging/dev avec différents proxies.
Si vous avez besoin que certaines requêtes passent par le proxy et d'autres directement, créez deux beans distincts RestTemplate avec des noms différents et utilisez @Qualifier pour injecter le bon.
Proxy dans Spring WebClient (stack réactif)
WebClient est le client HTTP réactif de Spring, construit sur Reactor Netty. Il ne lit pas les propriétés système de la JVM pour les proxies — la configuration se fait via ProxyProvider lors de la création du client.
Dépendance (incluse dans spring-boot-starter-webflux) :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Configuration de WebClient avec un proxy HTTP :
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
HttpClient httpClient = HttpClient.create()
.proxy(proxy -> proxy
.type(ProxyProvider.Proxy.HTTP)
.host("proxy.example.com")
.port(8080)
.username("user")
.password(user -> "password")
);
ClientHttpConnector connector =
new ReactorClientHttpConnector(httpClient);
return WebClient.builder()
.clientConnector(connector)
.build();
}
}
Pour les proxies SOCKS5 dans WebClient :
HttpClient httpClient = HttpClient.create()
.proxy(proxy -> proxy
.type(ProxyProvider.Proxy.SOCKS5)
.host("socks5.proxy.example.com")
.port(1080)
.username("user")
.password(user -> "password")
);
💡 Conseil de configuration
Dans les applications réactives, il est souvent nécessaire de créer plusieurs instances de WebClient avec différents proxies pour différents services externes. Utilisez WebClient.Builder comme bean prototype et redéfinissez les paramètres via .mutate().
Configuration du proxy dans OkHttp
OkHttp est une bibliothèque HTTP populaire utilisée par de nombreuses applications Java et Android, ainsi que certaines intégrations Spring (par exemple, Feign avec un backend OkHttp). Elle dispose de son propre mécanisme de configuration de proxy et n'utilise également pas les propriétés système de la JVM.
Configuration de base du proxy HTTP/HTTPS dans OkHttp :
import okhttp3.*;
import java.net.InetSocketAddress;
import java.net.Proxy;
// Création du proxy
Proxy proxy = new Proxy(
Proxy.Type.HTTP,
new InetSocketAddress("proxy.example.com", 8080)
);
// Authentification du proxy
Authenticator proxyAuthenticator = (route, response) -> {
String credential = Credentials.basic("username", "password");
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
};
// Construction du client
OkHttpClient client = new OkHttpClient.Builder()
.proxy(proxy)
.proxyAuthenticator(proxyAuthenticator)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
// Exemple de requête
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
try (Response response = client.newCall(request).execute()) {
System.out.println(response.body().string());
}
Intégration d'OkHttp avec Spring Boot via un bean :
@Configuration
@ConditionalOnProperty(name = "proxy.enabled", havingValue = "true")
public class OkHttpConfig {
@Value("${proxy.host}")
private String proxyHost;
@Value("${proxy.port}")
private int proxyPort;
@Bean
public OkHttpClient okHttpClient() {
Proxy proxy = new Proxy(
Proxy.Type.HTTP,
new InetSocketAddress(proxyHost, proxyPort)
);
return new OkHttpClient.Builder()
.proxy(proxy)
.connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES))
.build();
}
}
Notez l'utilisation de @ConditionalOnProperty — cela permet d'activer le proxy uniquement dans les environnements nécessaires via la configuration, sans modifier le code.
Si vous utilisez OkHttp avec des proxies résidentiels pour l'analyse de données, il est important de configurer correctement le pool de connexions. Les proxies résidentiels ont souvent une latence plus élevée par rapport aux proxies de centre de données, donc augmentez les timeouts et réduisez la taille du pool pour ne pas épuiser les connexions disponibles.
Proxy SOCKS5 en Java : caractéristiques et exemples
SOCKS5 est un protocole de niveau inférieur par rapport aux proxies HTTP. Il fonctionne au niveau de transport et prend en charge tous les protocoles (HTTP, HTTPS, FTP, etc.), ainsi que la résolution DNS côté proxy. Pour les applications Java, SOCKS5 est particulièrement utile lorsqu'il est nécessaire de proxy non seulement HTTP, mais aussi d'autres connexions TCP.
SOCKS5 via les propriétés système de la JVM :
System.setProperty("socksProxyHost", "socks5.proxy.example.com");
System.setProperty("socksProxyPort", "1080");
System.setProperty("java.net.socks.username", "user");
System.setProperty("java.net.socks.password", "password");
SOCKS5 dans OkHttp (via java.net.Proxy) :
Proxy socks5Proxy = new Proxy(
Proxy.Type.SOCKS,
new InetSocketAddress("socks5.proxy.example.com", 1080)
);
OkHttpClient client = new OkHttpClient.Builder()
.proxy(socks5Proxy)
.build();
Caractéristique importante de SOCKS5 et DNS : Par défaut, Java résout DNS localement et transmet déjà l'adresse IP via le proxy. Cela peut révéler la véritable requête DNS. Pour que la résolution DNS passe également par le proxy, utilisez l'approche suivante avec OkHttp :
// DNS personnalisé qui force la résolution via SOCKS5
OkHttpClient client = new OkHttpClient.Builder()
.proxy(socks5Proxy)
.dns(hostname -> {
// Retourne l'hôte non résolu — OkHttp le transmettra au proxy
return Collections.singletonList(InetAddress.getByName(hostname));
})
.build();
Quand choisir SOCKS5 vs HTTP Proxy
| Critère | Proxy HTTP | Proxy SOCKS5 |
|---|---|---|
| Protocoles | HTTP/HTTPS | Tous les TCP/UDP |
| DNS via le proxy | Dépend de l'implémentation | Pris en charge |
| Compatibilité avec Java | Native | Native (java.net.Proxy.Type.SOCKS) |
| Utilisation | Passerelles d'entreprise, web scraping | Anonymisation, protocoles non standards |
Rotation des proxies dans les applications Java
Si une application effectue un grand nombre de requêtes à une seule ressource, l'utilisation d'une seule IP de proxy entraînera rapidement un blocage. La rotation des proxies — le changement entre différentes adresses IP — résout ce problème. En Java, cela peut être réalisé de plusieurs manières.
Option 1 : Rotation via un point de terminaison de proxy tournant
L'approche la plus simple consiste à utiliser un fournisseur de proxy avec un point de terminaison unique qui change automatiquement d'IP à chaque requête ou à intervalles réguliers. Vous spécifiez un hôte et un port, et la rotation se fait côté fournisseur. Aucun code de rotation n'est nécessaire.
Option 2 : Rotation côté application via une liste de proxies
@Component
public class ProxyRotator {
private final List<ProxyConfig> proxies;
private final AtomicInteger counter = new AtomicInteger(0);
public ProxyRotator(@Value("${proxy.list}") List<String> proxyList) {
this.proxies = proxyList.stream()
.map(this::parseProxy)
.collect(Collectors.toList());
}
public OkHttpClient getClientWithNextProxy() {
int index = counter.getAndIncrement() % proxies.size();
ProxyConfig config = proxies.get(index);
Proxy proxy = new Proxy(
Proxy.Type.HTTP,
new InetSocketAddress(config.getHost(), config.getPort())
);
return new OkHttpClient.Builder()
.proxy(proxy)
.build();
}
private ProxyConfig parseProxy(String proxyStr) {
// Analyse la chaîne de type "host:port" ou "user:pass@host:port"
String[] parts = proxyStr.split(":");
return new ProxyConfig(parts[0], Integer.parseInt(parts[1]));
}
}
Option 3 : Rotation via ProxySelector
Java fournit un mécanisme intégré ProxySelector, qui permet de sélectionner dynamiquement un proxy en fonction de l'URL de destination. Cela fonctionne avec HttpURLConnection et Apache HttpClient :
ProxySelector.setDefault(new ProxySelector() {
private final List<Proxy> proxyPool = Arrays.asList(
new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy1.example.com", 8080)),
new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy2.example.com", 8080)),
new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy3.example.com", 8080))
);
private final AtomicInteger idx = new AtomicInteger(0);
@Override
public List<Proxy> select(URI uri) {
// Vous pouvez ajouter une logique de sélection par domaine
int i = idx.getAndIncrement() % proxyPool.size();
return Collections.singletonList(proxyPool.get(i));
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
// Logique de traitement d'un proxy inaccessible
log.warn("Proxy échoué : {}", sa);
}
});
Quel type de proxy choisir pour les tâches Java
Le choix du type de proxy dépend de la tâche spécifique. Pour les applications Java d'entreprise, trois types principaux sont généralement envisagés :
| Type de proxy | Vitesse | Anonymat | Meilleur pour |
|---|---|---|---|
| Proxies de centre de données | Élevée | Moyenne | Analyse de données publiques, tests d'API, charge élevée |
| Proxies résidentiels | Moyenne | Élevée | Analyse de sites sécurisés, tests géographiques, contournement des blocages |
| Proxies mobiles | Moyenne | Maximale | Intégrations avec des API mobiles, services avec une forte protection anti-fraude |
Recommandations pratiques par type de tâche :
- Passerelle d'entreprise (Squid, Zscaler) : Le type de proxy est déterminé par le département informatique. Utilisez un proxy HTTP avec authentification via Apache HttpClient ou les propriétés système de la JVM.
- Analyse de données publiques (actualités, cotations, API ouvertes) : Les proxies de centre de données sont le choix optimal en termes de rapport vitesse/coût.
- Analyse de e-commerce (Wildberries, Ozon, Amazon) : Proxies résidentiels avec rotation. Ces plateformes bloquent activement les IP de centre de données.
- Tests géographiques (vérification de la localisation, prix par région) : Proxies résidentiels avec sélection de pays/ville.
- Intégration avec des services et applications mobiles : Les proxies mobiles — les IP provenant de réseaux mobiles réels imitent le mieux les utilisateurs réels.
Erreurs fréquentes lors de la configuration de proxies en Java et comment les corriger
Même les développeurs expérimentés rencontrent les mêmes problèmes lors de la configuration de proxies en Java. Examinons les plus courants.
1. Proxy configuré, mais le trafic passe toujours directement
Cause : Vous avez défini les propriétés système de la JVM, mais vous utilisez OkHttp ou Reactor Netty (WebClient), qui les ignorent.
Solution : Configurez le proxy explicitement dans la configuration du client HTTP spécifique, comme indiqué dans les sections ci-dessus.
2. javax.net.ssl.SSLHandshakeException lors de l'utilisation de HTTPS via un proxy
Cause : Le proxy d'entreprise effectue une inspection SSL (MITM), en remplaçant le certificat. Java ne fait pas confiance au CA d'entreprise.
Solution : Importez le certificat d'entreprise dans le truststore de Java :
keytool -import -trustcacerts \ -alias corporate-ca \ -file corporate-ca.crt \ -keystore $JAVA_HOME/lib/security/cacerts \ -storepass changeit
3. java.net.ConnectException : Connexion refusée
Causes : Hôte ou port de proxy incorrect ; serveur proxy inaccessible ; pare-feu bloquant la connexion.
Diagnostic :
# Vérifiez l'accessibilité du proxy curl -x http://proxy.example.com:8080 https://httpbin.org/ip # Ou via telnet telnet proxy.example.com 8080
4. Le proxy fonctionne pour HTTP, mais pas pour HTTPS
Cause : Seules les propriétés http.proxyHost/Port sont définies, mais pas https.proxyHost/Port.
Solution : Définissez les deux ensembles de propriétés. Pour HTTPS via un proxy HTTP, la méthode de tunneling CONNECT est utilisée — assurez-vous que le proxy la prend en charge.
5. 407 Proxy Authentication Required
Cause : Le proxy nécessite une authentification, mais elle n'est pas configurée.
Solution : Ajoutez un Authenticator pour les propriétés système de la JVM ou configurez un CredentialsProvider pour Apache HttpClient / proxyAuthenticator pour OkHttp (exemples ci-dessus).
6. Fuite de mémoire lors de la rotation des proxies
Cause : Un nouvel instance de OkHttpClient est créée à chaque requête. Chaque client maintient son propre pool de threads et de connexions.
Solution : Réutilisez les clients. Créez un pool de plusieurs clients (un par proxy) et faites-les tourner, plutôt que de créer de nouveaux clients.
7. Activation de la journalisation de débogage pour le diagnostic
# application.properties — activez les logs pour le diagnostic du proxy logging.level.org.apache.http=DEBUG logging.level.org.apache.http.wire=DEBUG logging.level.reactor.netty.http.client=DEBUG # Pour la JVM — propriété système -Djava.net.debug=all
Conclusion
La configuration des proxies dans les applications Java nécessite une compréhension du client HTTP utilisé en arrière-plan. Les propriétés système de la JVM sont un bon point de départ pour HttpURLConnection, mais OkHttp, WebClient et Apache HttpClient nécessitent une configuration explicite. Pour les applications d'entreprise, il est recommandé de sortir les paramètres du proxy dans application.properties et d'utiliser des profils Spring pour différents environnements. La rotation des proxies est mieux déléguée à un fournisseur avec un point de terminaison tournant — c'est plus simple et plus fiable que de le réaliser soi-même.
Si votre application Java effectue de l'analyse de données sur des plateformes sécurisées ou nécessite une grande anonymité lors des requêtes externes, nous vous recommandons d'envisager des proxies résidentiels — ils disposent d'IP réelles d'utilisateurs domestiques, ce qui réduit considérablement le risque de blocages par les systèmes anti-fraude. Pour l'analyse à fort volume de données publiques, les proxies de centre de données sont optimaux — ils offrent la vitesse maximale à un coût de trafic réduit.
```