Introduction
Les problèmes réseau React Native se déguisent souvent en bogues d'application alors que les vrais coupables sont le DNS, les ports, le routage, les pare-feu, les proxys ou le TLS. La voie la plus rapide vers une solution est une approche disciplinée et mesurable : commencez par un test de santé ciblé, vérifiez depuis le runtime d'appareil que vous utilisez réellement (émulateur Android, simulateur iOS ou appareil physique), puis élargissez seulement après avoir obtenu une référence verte.
Ce guide est orienté praticien. Vous allez inventorier versions et topologie, appliquer une configuration sûre et réversible, exécuter des diagnostics concrets avec résultats attendus, associer les échecs courants à leurs correctifs, et utiliser une liste de contrôle reproductible d'un projet à l'autre. Le même manuel fonctionne que vous construisiez avec React Native pur ou Expo, et que votre backend soit REST, GraphQL ou une autre API.
Inventaire des versions et de l'environnement
Avant de modifier des réglages, capturez l'environnement exact. Cela évite de poursuivre des différences entre machines et rend les problèmes reproductibles.
Enregistrer les versions de l'application et de l'outillage
node -v
npm -v
# ou si vous utilisez yarn ou pnpm
yarn -v
pnpm -v
npx react-native info
adb version
emulator -version
xcodebuild -version
xcrun simctl list devices
Capturer le contexte appareil/runtime
- Utilisez-vous l'émulateur Android, le simulateur iOS, Expo Go ou un appareil physique ?
- L'appareil est-il sur le même réseau local que votre machine de développement ?
- Un VPN ou un proxy d'entreprise est-il activé ?
Capturer les points de terminaison et ports du backend
- URLs exactes incluant schéma et port, par exemple :
https://api.exemple.local:8443/healthzhttp://192.168.1.50:3000/ping- Domaines de recherche DNS ou DNS à horizon partagé dont vous dépendez.
Instantané de la configuration réseau sur votre machine de développement
macOS :
scutil --dns
networksetup -getwebproxy Wi-Fi
ifconfig
Linux :
resolvectl status || systemd-resolve --status
ip addr
ip route
Windows (PowerShell) :
Get-DnsClientServerAddress
Get-NetIPConfiguration
netsh winhttp show proxy
Choisissez un point de terminaison de santé simple et un runtime (par exemple, l'émulateur Android). Visez d'abord une requête HEAD ou GET 200 OK réussie. Étendez aux autres runtimes seulement après vérification. Un pilote étroit et mesurable est plus facile à inspecter localement et évite de combiner les variables.
Choisir une cible pilote minimale
Chemin de configuration sûr
Utilisez les bons noms d'hôtes et des réglages réversibles. Le tableau ci-dessous indique la bonne façon d'atteindre votre machine de développement depuis différents runtimes.
| Runtime | Hôte pour atteindre votre machine de dev | Mapping de port optionnel | Notes |
|---|---|---|---|
| Émulateur Android (AVD) | http://10.0.2.2 | adb reverse tcp:3000 tcp:3000 | 10.0.2.2 pointe vers la boucle locale de l'hôte. Le mapping inverse permet à un appareil physique d'atteindre les ports de l'hôte. |
| Appareil Android (USB) | http://127.0.0.1 avec adb reverse, ou http://<IP_LAN> | adb reverse tcp:3000 tcp:3000 | Sans reverse, utilisez l'IP LAN de votre machine sur le même réseau. |
| Simulateur iOS | http://localhost | Non requis | Le simulateur partage la pile réseau de l'hôte. |
| Appareil iOS (Wi-Fi) | http://<IP_LAN> | Non disponible | Assurez-vous que l'appareil et la machine sont sur le même LAN. |
| Expo Go (Android) | http://10.0.2.2 (émulateur) ou http://<IP_LAN> (appareil) | adb reverse optionnel | Expo Go utilise le réseau de l'appareil ; les mêmes règles s'appliquent. |
Principaux motifs sûrs (développement seulement)
Mapping de port de développement Android avec adb reverse
adb reverse tcp:3000 tcp:3000
# supprimer les mappings quand terminé
adb reverse --remove-all
Si votre API de développement est en http (pas https), ajoutez une configuration de sécurité réseau en mode debug seulement et référencez-la depuis le manifeste debug. Exemple : android/app/src/debug/res/xml/network_security_config.xml
Autorisation cleartext en développement seulement (Android)
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">192.168.1.50</domain>
</domain-config>
</network-security-config>
Dans android/app/src/debug/AndroidManifest.xml :
<application
android:networkSecurityConfig="@xml/network_security_config"
...>
</application>
Supprimez pour les builds de production.
Pour les points de terminaison http pendant le développement seulement, ajoutez à ios/<App>/Info.plist sous une configuration debug :
Relaxation ATS en développement seulement (iOS)
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Supprimez avant de livrer. Préférez HTTPS de bout en bout.
Préférez faire confiance à un certificat d'autorité locale au niveau OS. Sur Android 7+, si vous avez besoin que l'application fasse confiance aux AC installées par l'utilisateur pendant le développement, déclarez une configuration de sécurité réseau debug-only qui fait confiance aux certificats utilisateur. Sur iOS, installez le profil d'AC et marquez-le comme approuvé pour SSL.
TLS auto-signé en développement
CORS est un modèle de sécurité navigateur ; les piles réseau React Native ne l'appliquent pas de la même façon. Si votre serveur bloque les requêtes à cause d'Origin ou d'en-têtes personnalisés, c'est une politique côté serveur, pas une limitation du runtime client.
Ne pas supposer CORS dans React Native
Certains réseaux mobiles préfèrent IPv6. Utilisez des noms d'hôtes explicites et assurez-vous que votre DNS renvoie des enregistrements que votre service supporte. Si vous vous connectez par IP littérale, préférez les adresses IPv4 quand votre service est IPv4-only.
IPv4 vs IPv6
Vérification et diagnostics
Suivez ces étapes dans l'ordre. Arrêtez-vous quand vous obtenez un résultat vert ; puis élargissez la portée au runtime ou point de terminaison suivant.
1. Confirmer la connectivité au niveau application avec NetInfo
import NetInfo from "@react-native-community/netinfo\);n
NetInfo.fetch().then(state => {
console.log("isConnected:" state.isConnected);
console.log("isInternetReachable:" state.isInternetReachable);
});
Résultat attendu : isConnected true et isInternetReachable true sur un réseau fonctionnel. Si faux, résolvez la connectivité de l'appareil (Wi-Fi, cellulaire, portail captif) avant de continuer.
2. Tester une requête HEAD simple depuis l'application
Utilisez un minuscule point de terminaison comme /healthz qui ne fait aucun travail lourd.
// Exemple : fetch robuste avec timeout via AbortController
const withTimeout = (ms, controller) => setTimeout(() => controller.abort(), ms);
async function checkHealth(url) {
const controller = new AbortController();
const timer = withTimeout(5000, controller);
try {
const res = await fetch(url, { method: 'HEAD', signal: controller.signal });
console.log('status', res.status);
return res.ok;
} catch (e) {
console.log('error', String(e));
return false;
} finally {
clearTimeout(timer);
}
}
// Choisissez le bon hôte : voir tableau ci-dessus
checkHealth('http://10.0.2.2:3000/healthz');
Résultat attendu : status 200. Si l'erreur inclut TypeError: Network request failed, continuez ci-dessous.
3. Isoler DNS vs transport
Depuis votre machine de développement, résolvez et connectez-vous au nom d'hôte exact utilisé dans l'application.
macOS/Linux :
dig +short api.exemple.local
nc -vz api.exemple.local 3000
Windows (PowerShell) :
Resolve-DnsName api.exemple.local
Test-NetConnection api.exemple.local -Port 3000
Résultat attendu : le DNS renvoie au moins une adresse ; le test de port réussit. Si le DNS échoue mais que l'IP fonctionne, mettez à jour votre configuration d'application pour utiliser un hôte accessible (IP LAN pour le dev) ou corrigez les règles DNS à horizon partagé.
4. Vérifier l'accessibilité du port depuis le runtime d'appareil
- L'émulateur Android hérite de l'accessibilité de l'hôte vers 10.0.2.2. Si vous vous connectez à une IP LAN à la place, assurez-vous que le pare-feu de l'hôte autorise l'entrant sur ce port.
- Appareil Android physique : préférez
adb reversepour le développement local, ou ouvrez le pare-feu vers votre IP LAN et testez viahttp://<IP_LAN>. - Le simulateur iOS utilise le réseau de l'hôte ; localhost fonctionne.
- Appareil iOS physique : assurez-vous du même Wi-Fi et ouvrez le pare-feu.
Vérifications pare-feu hôte
macOS (PF) :
sudo pfctl -s rules
lsof -iTCP -sTCP:LISTEN -P | grep 3000
Linux (UFW ou iptables) :
sudo ufw status verbose
sudo ss -ltnp | grep :3000
Windows :
Get-NetFirewallProfile
Get-NetFirewallRule | Select-String -Pattern 3000
netstat -ano | findstr :3000
Résultat attendu : votre processus serveur écoute, et le pare-feu autorise l'entrant sur la bonne interface.
5. Vérifier le routage et les proxys
Si un proxy système est configuré, les runtimes mobiles peuvent l'honorer.
macOS :
networksetup -getwebproxy Wi-Fi
Windows :
netsh winhttp show proxy
Linux :
env | egrep 'https?_proxy|HTTPS?_PROXY'
Résultat attendu : soit pas de proxy non intentionnel, soit des règles de proxy qui autorisent vos requêtes.
6. Observer les logs sur les échecs
Android :
adb logcat | egrep -i 'okhttp|ssl|connect|react|fatal'
Cherchez SSLHandshakeException, UnknownHostException, ou ConnectException.
iOS : ouvrez Console.app, filtrez sur votre processus, ou consultez les logs Xcode. Cherchez les codes NSURLErrorDomain tels que -1003 (hôte introuvable), -1200 (échec TLS), -1004 (impossible de se connecter à l'hôte), -1001 (timeout).
7. Vérification TLS
Utilisez l'URL https complète dans l'application et confirmez que la chaîne de certificats est valide pour l'appareil. Si vous utilisez une AC locale pour le dev, assurez-vous que l'AC est approuvée par l'appareil et, sur Android, autorisée par votre configuration de sécurité réseau debug.
8. Relance et backoff (résilience client)
Ajoutez des relances bornées pour les problèmes réseau transitoires.
async function retry(fn, retries = 2, base = 300) {
let attempt = 0;
while (true) {
try { return await fn(); }
catch (e) {
if (attempt++ >= retries) throw e;
const delay = base * Math.pow(2, attempt - 1);
await new Promise(r => setTimeout(r, delay));
}
}
}
await retry(() => checkHealth('http://10.0.2.2:3000/healthz'));
Résultat attendu : les échecs transitoires récupèrent en quelques tentatives. Les échecs persistants doivent quand même ressortir clairement.
Modes de défaillance et récupération
Utilisez ce mappage pour passer rapidement du symptôme au correctif.
| Symptôme ou erreur | Cause probable | Correctif ciblé |
|---|---|---|
ERR_NAME_NOT_RESOLVED, UnknownHostException, NSURLErrorDomain -1003 | Le DNS ne résout pas depuis le runtime d'appareil | Utilisez le bon hôte pour le runtime (10.0.2.2, localhost, ou IP LAN). Corrigez le DNS ou utilisez l'IP LAN en dev. |
ECONNREFUSED, impossible de se connecter, connexion refusée | Port fermé ou serveur pas en écoute | Démarrez le serveur, vérifiez l'adresse d'écoute 0.0.0.0, ouvrez le pare-feu, confirmez le port avec netstat/ss. |
Timeout ou NSURLErrorDomain -1001 | Pare-feu, proxy, ou routage qui coupe ; serveur lent | Contournez le proxy, ouvrez le pare-feu, testez nc/Test-NetConnection, ajoutez un point de terminaison de santé serveur. |
SSLHandshakeException, NSURLErrorDomain -1200 | Certificat invalide ou AC non approuvée | Utilisez HTTPS avec certificat valide, approuvez l'AC locale sur l'appareil, ajoutez une config de confiance debug-only sur Android. |
| Fonctionne dans le simulateur, échoue sur l'appareil | Mauvais hôte (localhost) ou isolation LAN | Utilisez l'IP LAN sur les appareils ; assurez-vous du même Wi-Fi ; envisagez adb reverse pour Android USB. |
| Problèmes réseau IPv6-only | Service accessible seulement via IPv4 | Assurez-vous que le DNS renvoie des AAAA ou utilisez dual-stack ; évitez les URLs littérales IPv4 en dur sur réseaux IPv6-only. |
| POST/PUT échouent, GET fonctionne | Le serveur rejette en-têtes/taille du corps | Inspectez les logs serveur ; ajustez Content-Type, corps, et limites serveur. |
| Croyance que CORS bloque les requêtes | RN n'applique pas le CORS navigateur | Corrigez la politique serveur si elle bloque Origin ; ce n'est pas une restriction client React Native. |
Récupération et annulation
- Supprimez les mappings adb reverse quand terminé :
adb reverse --remove-all
- Annulez les relaxations réseau debug-only (manifeste Android, ATS iOS) avant tout build de production.
- Si vous avez modifié des règles de pare-feu OS, documentez et revenez à la référence de l'équipe une fois les tests de développement terminés.
- Si vous avez installé une AC locale sur des appareils pour le dev, supprimez-la des appareils non utilisés pour le développement.
Exemples pratiques
Basculer localhost vers le bon hôte par runtime
Émulateur Android :
const API = 'http://10.0.2.2:3000';
Simulateur iOS :
const API = 'http://localhost:3000';
Appareil physique sur LAN (remplacez par l'IP réelle) :
const API = 'http://192.168.1.50:3000';
Upload de fichier avec timeout explicite et surface d'erreur
async function uploadImage(uri) {
const data = new FormData();
data.append('file', { uri, type: 'image/jpeg', name: 'photo.jpg' });
const controller = new AbortController();
const t = setTimeout(() => controller.abort(), 15000);
try {
const res = await fetch(`${API}/upload`, {
method: 'POST',
body: data,
headers: { 'Accept': 'application/json' },
signal: controller.signal,
});
if (!res.ok) throw new Error(`Upload failed ${res.status}`);
return await res.json();
} finally {
clearTimeout(t);
}
}
Résultat attendu : réponse 200 ou 201 avec corps JSON ; sur annulation, affichez une erreur claire pour que l'utilisateur puisse réessayer.
Garde-fou de connectivité avant d'appeler les APIs
async function guardedFetch(url, init) {
const s = await NetInfo.fetch();
if (!s.isConnected || !s.isInternetReachable) {
throw new Error('Pas de connexion internet');
}
return fetch(url, init);
}
Cela évite de spammer votre backend quand l'appareil est hors ligne.
Bibliothèque de commandes rapides
Utilisez ces commandes pour tester la résolution DNS et l'accessibilité des ports depuis votre machine de développement.
| OS | Vérification DNS | Vérification port | Notes |
|---|---|---|---|
| macOS | dig +short hote.exemple | nc -vz hote.exemple 3000 | Utilisez aussi scutil --dns pour détails resolveurs. |
| Linux | getent hosts hote.exemple | nc -vz hote.exemple 3000 | resolvectl status pour DNS par liaison. |
| Windows | Resolve-DnsName hote.exemple | Test-NetConnection hote.exemple -Port 3000 | Ajoutez -InformationLevel Detailed pour plus de sortie. |
Résultats attendus
- La vérification DNS renvoie au moins une IP.
- La vérification port rapporte succès ; sinon, investiguez pare-feu, adresse d'écoute, ou routage.
Liste de contrôle opérationnelle
Utilisez cette liste répétable sur chaque problème réseau React Native.
- Inventaire
- Enregistrez RN, OS, appareil/émulateur, et URLs et ports du backend.
- Notez statut VPN/proxy et pare-feu.
- Choisir un pilote
- Choisissez un runtime (ex. émulateur Android) et un point de terminaison de santé.
- Configurer en sécurité
- Utilisez l'hôte correct (10.0.2.2, localhost, ou IP LAN).
- Optionnellement utilisez adb reverse pour le développement Android.
- Ajoutez les relaxations réseau debug-only si absolument requis ; documentez-les.
- Vérifier étape par étape
- Vérifiez la connectivité NetInfo depuis l'application.
- Faites une requête HEAD avec timeout 5s ; attendez 200.
- Depuis votre machine, résolvez le DNS et testez le port.
- Confirmez que le serveur écoute et que le pare-feu autorise l'entrant.
- Observer les logs
- Android :
adb logcatpour erreurs okhttp/ssl/connect. - iOS : Xcode ou Console pour codes NSURLErrorDomain.
- Corriger par mode de défaillance
- Mauvais hôte : utilisez l'hôte approprié au runtime.
- Port fermé : démarrez le serveur, écoutez sur 0.0.0.0, ouvrez le pare-feu.
- DNS cassé : utilisez l'IP LAN en dev ou corrigez le DNS.
- TLS cassé : approuvez l'AC de dev ou utilisez certificats valides ; supprimez les relaxations après.
- Annuler
- Supprimez les mappings adb reverse.
- Supprimez les exceptions réseau debug-only.
- Revenez aux règles de pare-feu de référence de l'équipe.
Conclusion
Le réseau React Native devient prévisible quand vous le traitez comme une séquence d'étapes observables : inventaire, choix d'un pilote étroit, application d'une configuration sûre et réversible, vérification depuis le runtime réel, et expansion seulement après un test vert net. Avec la bonne sélection d'hôte, des tests DNS et port clairs, et des logs ciblés, vous pouvez isoler les problèmes en minutes au lieu de jours. Gardez les relaxations de développement strictement debug-only, documentez chaque changement, et annulez-les dès que vos vérifications passent. Cette approche s'échelonne du développeur individuel aux équipes de démarrage et mandats de conseil tout en gardant le risque bas et les résultats mesurables.