Échec de la requête réseau React Native fetch ()

146

Lorsque je crée un tout nouveau projet en utilisant react-native init(RN version 0.29.1) et que je mets une extraction dans la méthode de rendu sur l'API publique du film de démonstration Facebook, cela lance un fichier Network Request Failed. Il y a une trace de pile très inutile et je ne peux pas déboguer les requêtes réseau dans la console Chrome. Voici la récupération que j'envoie:

fetch('http://facebook.github.io/react-native/movies.json')
      .then((response) => response.json())
      .then((responseJson) => {
        return responseJson.movies;
      })
      .catch((error) => {
        console.error(error);
      });
Alek Hurst
la source
1
Je ne suis pas sûr. J'utilise le simulateur iOS et je pensais qu'il utilisait la connexion Internet de mon ordinateur
Alek Hurst
Essayez de charger le simulateur manuellement et d'ouvrir l'url dans safari
FuzzyTree
5
http-> https(si possible) résoudra très probablement votre problème
Nick Zuber
1
J'utilisais l'adresse IP 192.168.1.25:3000de ifconfigsans lier mon serveur à cette adresse IPrails server --binging=192.168.1.25 --port=3000
Fabrizio Bertoglio
1
Oui j'ai tout essayé. Rien n'a fonctionné pour moi
Vigneswaran A

Réponses:

140

Le problème ici est qu'iOS n'autorise pas les requêtes HTTP par défaut, uniquement HTTPS. Si vous souhaitez activer les requêtes HTTP, ajoutez ceci à votre info.plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
Alek Hurst
la source
2
Cette réponse a fonctionné pour moi. Pour les autres nouveaux utilisateurs de React Native, ce fichier (info.plist) peut également être modifié via xcode: stackoverflow.com/a/38219454/1299792
Marklar
86
et Android? Je suis également confronté au même problème sous Android.
Vijay Sharma
16
Exactement. Quelqu'un a la réponse pour Android?
Zach Cook
1
quand je le mets sur ios / build / info.plist et que je lance: react-native run-ios Le ios / build / info.plist est écrasé et quitte mes modifications Que dois-je faire?
Jorge Wander Santana Ureña
1
@ JorgeWanderSantanaUreña modifier [votre_nom_dossier_projet] / ios / [votre_nom_dossier_projet] / In‌ fo.plist
kgosse
58

Il n'est pas recommandé d'autoriser tous les domaines pour http. Faites une exception uniquement pour les domaines nécessaires.

Source: Configuration des exceptions de sécurité de transport d'application dans iOS 9 et OSX 10.11

Ajoutez ce qui suit au fichier info.plist de votre application:

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>yourserver.com</key>
    <dict>
      <!--Include to allow subdomains-->
      <key>NSIncludesSubdomains</key>
      <true/>
      <!--Include to allow HTTP requests-->
      <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
      <true/>
      <!--Include to specify minimum TLS version-->
      <key>NSTemporaryExceptionMinimumTLSVersion</key>
      <string>TLSv1.1</string>
    </dict>
  </dict>
</dict>
Lavi Avigdor
la source
27
et Android?
arisalexis
3
Il semble y avoir plusieurs fichiers info.plist dans plusieurs répertoires de mon application React Native. Une idée du dossier contenant le bon fichier à modifier?
Marklar
2
@Marklar [your_project_folder_name] / ios / [your_project_folder_name] /Info.plist
Stich
si j'utilise mon hôte local ici: <key> yourserver.com </key>, quand je suis prêt à publier, je vais devoir le changer, n'est-ce pas?
Anayo Oleru
36

J'utilisais localhostpour l'adresse, ce qui était évidemment faux. Après l'avoir remplacé par l'adresse IP du serveur (dans le réseau de l'émulateur), cela a parfaitement fonctionné.

Éditer

Dans Android Emulator, l'adresse de la machine de développement est 10.0.2.2. Plus d'explications ici

Pour Genymotion, l'adresse est 10.0.3.2. Plus d'infos ici

Mahmoodvcs
la source
4
Je vous remercie. Probablement la seule réponse que j'ai vue qui fonctionne pour Android. J'ai utilisé l'adresse IP de mon réseau et cela fonctionne. par exemplehttp://<Network IP emulator connects to>:<port where API is served>/api/tasks
Brandon Benefield
1
N'oubliez pas le "http: //" sinon cela ne fonctionnera pas ... je me demandais pourquoi cela fonctionnerait sur postman mais pas avec fetch
Moucheg
@Mahmoodvcs Votre réponse m'aide beaucoup, merci beaucoup, j'utilise l'émulateur Android.
Pena Pintada
14

Pour nous, c'était parce que nous téléchargions un fichier et que RN filePicker ne donnait pas le type de mime approprié. Cela nous a juste donné une «image» en tant que type. Nous devions le changer en 'image / jpg' pour que la récupération fonctionne.

form.append(uploadFileName, {
  uri : localImage.full,
  type: 'image/jpeg',
  name: uploadFileName
 })
NickJ
la source
@JohhanSantana Vous pourriez probablement regarder les données d'image brutes et les récupérer depuis le début, mais le sélecteur natif de réaction est juste revenu "image" pour moi.
NickJ
10

React Native Docs donne la réponse à cela.

Apple a bloqué le chargement implicite des ressources HTTP en clair. Nous devons donc ajouter le fichier Info.plist (ou équivalent) de notre projet suivant.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

React Native Docs -> Intégration avec des applications existantes -> Tester votre intégration -> Ajouter une exception de sécurité de transport d'application

océan
la source
9

Le problème peut provenir de la configuration du serveur.

Android 7.0 a un bogue décrit ici . Solution de contournement proposée par Vicky Chijwani:

Configurez votre serveur pour utiliser la courbe elliptique prime256v1. Par exemple, dans Nginx 1.10, vous faites cela en définissant ssl_ecdh_curve prime256v1;

Dmitry Maksakov
la source
7

J'ai eu le même problème sur Android mais j'ai réussi à trouver une solution. Android bloque le trafic en texte clair (demandes non https) depuis le niveau d'API 28 par défaut. Cependant, react-native ajoute une configuration de sécurité réseau à la version de débogage ( android/app/src/debug/res/xml/react_native_config.xml) qui définit certains domaines (localhost et les adresses IP de l'hôte pour AVD / Genymotion), qui peuvent être utilisés sans SSL en mode dev. Vous pouvez y ajouter votre domaine pour autoriser les requêtes http.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="false">localhost</domain>
    <domain includeSubdomains="false">10.0.2.2</domain>
    <domain includeSubdomains="false">10.0.3.2</domain>
    <domain includeSubdomains="true">dev.local</domain>
  </domain-config>
</network-security-config>
Johannes Spohr
la source
Cela a fonctionné pour moi avec react native 0.59 et target sdk 28 :)
sameera madushan
7

J'ai eu le même problème sur Android 9 à cause du "http" et le problème a été résolu en ajoutant simplement android: usesCleartextTraffic = "true" dans AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
  android:usesCleartextTraffic="true"
 .......>
 .......
</application>

kautikmistry
la source
2
Merci, cela a fonctionné pour moi aussi. Cela se produit parce qu'Android ne prend plus en charge HTTP par défaut sur l'API 28.
Gui Herzog
5

Je suis tombé sur le même problème sur l'émulateur Android, où j'ai essayé d'accéder à une URL HTTPS externe avec un certificat valide. Mais la récupération de cette URL dans React-Native a échoué

'fetch error:', { [TypeError: Network request failed]
sourceURL: 'http://10.0.2.2:8081/index.delta?platform=android&dev=true&minify=false' }

1) Pour trouver l'erreur exacte dans les journaux, j'ai d'abord activé `` Debug JS Remotely '' en utilisant Cmd + M sur l'application

2) L'erreur signalée était

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

3) J'ai ajouté le certificat valide de l'URL en utilisant cette méthode -> ÉTAPE 2

http://lpains.net/articles/2018/install-root-ca-in-android/

Ce certificat est ajouté à l'onglet Utilisateur.

4) Ajoutez l'attribut d' android:networkSecurityConfigattribut à AndroidManifest.xml

Ajouter un fichier de configuration de sécurité réseau res/xml/network_security_config.xml:

<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="user"/>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>

Cela devrait fonctionner et vous donner une réponse attendue.

henryoats
la source
J'avais juste besoin de faire l'étape 4 pour travailler. Merci!
Bruno Serrano
4

J'avais ce problème pour Android-

URL- localhost / authToken.json - n'a pas fonctionné :(

URL- 10.106.105.103/authToken.json - n'a pas fonctionné :(

URL- http://10.106.105.103/authToken.json - a fonctionné :): D

Remarque - Utiliser ifconfigsous Linux ou ipconfigsous Windows pour trouver la machine IpAddress

Varun Kumar
la source
4

Pour l'utilisateur Android:

  1. Remplacez localhosts par une adresse IP LAN car lorsque vous exécutez le projet sur un appareil Android, localhost pointe vers l'appareil Android, au lieu de votre ordinateur, exemple: changez http://localostenhttp://192.168.1.123

  2. Si votre URL de demande est HTTPS et que votre appareil Android est sous un proxy, supposez que vous avez installé CA ajouté par l'utilisateur (comme CA de burp suite ou CA de Charles) sur votre appareil Android, assurez-vous que votre version Android est inférieure à Nougat (7.0) , car : Modifications des autorités de certification approuvées dans Android Nougat

    Autorités de certification ajoutées par l'utilisateur La
    protection de toutes les données d'application est un objectif clé du sandbox d'application Android. Android Nougat modifie la façon dont les applications interagissent avec les autorités de certification fournies par les utilisateurs et les administrateurs. Par défaut, les applications qui ciblent le niveau d'API 24 ne respecteront pas, de par leur conception, ces autorités de certification, à moins que l'application ne les opte explicitement. Ce paramètre de sécurité par défaut réduit la surface d'attaque des applications et encourage une gestion cohérente des données d'application basées sur le réseau et les fichiers.

crocs
la source
3

Pour Android, vous avez peut-être manqué d'ajouter l'autorisation dans AndroidManifest.xml. Vous devez ajouter l'autorisation suivante.

<uses-permission android:name="android.permission.INTERNET" /> 
Shashwat
la source
J'ai déjà cela même si j'obtiens cette erreur, existe-t-il une autre solution de contournement?
masud_moni
@masud_moni trouvez-vous un moyen de résoudre le problème? J'ai toujours le même problème
Rafael Rotiroti
@RafaelRotiroti oui j'ai résolu ce problème, mais même si cela fait un moment, il est difficile de s'en souvenir, si vous avez utilisé l'autorisation et que vous rencontrez toujours des problèmes, veuillez partager les détails. Je ferai de mon mieux pour vous aider, et vous en aurez d'autres pour l'examiner
masud_moni
@masud_moni merci, j'ai résolu ce problème en utilisant l'adresse IP donnée après l'exécution de la commande ifconfig. AVD crée un appareil virtuel, donc en utilisant la même théorie que les machines virtuelles qui ne sont rien hébergées dans 127.0.0.1 sur mon appareil. J'utilise donc l'adresse IP 192.168.xx et tout fonctionne bien aussi
Rafael Rotiroti
2

J'ai un problème similaire. Dans mon cas, les demandes à localhost fonctionnaient et se sont soudainement arrêtées. Il s'est avéré que le problème était que je désactivais mon wifi sur mon téléphone Android.

Ивайло Янков
la source
2

Cela a fonctionné pour moi, Android utilise un type spécial d'adresse IP 10.0.2.2 puis le numéro de port

import { Platform } from 'react-native';

export const baseUrl = Platform.OS === 'android' ?
    'http://10.0.2.2:3000/'
: 
'http://localhost:3000/';
Cho Cho
la source
1

si vous utilisez docker pour le reste api, un cas de travail pour moi était de remplacer le nom d' hôte: http://demo.test/apil'adresse IP de la machine: http://x.x.x.x/api. Vous pouvez obtenir l'IP en vérifiant quel ipv4 vous avez sur votre réseau sans fil. Vous devriez également avoir le wifi du téléphone.

Craciun Ciprian
la source
1

Vous devez gérer le cas d'erreur dans .then pour extraire l'API.

Par exemple:

fetch(authURl,{ method: 'GET'})
.then((response) => {      
  const statusCode = response.status;
  console.warn('status Code',statusCode);
  if(statusCode==200){
    //success code
  }else{
    //handle other error code
  }      
},(err) => {
  console.warn('error',err)
})
.catch((error) => {
  console.error(error);
  return error;
});
user3374790
la source
0
  1. Ajoutez une android:usesCleartextTraffic="true"ligne dans AndroidManifest.xml.

  2. Supprimez tous les dossiers de débogage de votre dossier Android.

devkrkanhaiya
la source
0

Vous pouvez le gérer en utilisant ceci:

catch((error) => {
      this.setState({
        typing_animation_button: false,
      });
      console.log(error);
      if ('Timeout' || 'Network request failed') {
        toast_show = true;
        toast_type = 'error';
        toast_text = 'Network failure';
      }
      this.setState({
        disable_button: false,
      });
    });
Talha Fiaz
la source
-1

Juste vous avez des changements dans Fetch ...

fetch('http://facebook.github.io/react-native/movies.json')
    .then((response) => response.json())
    .then((responseJson) => {
        /*return responseJson.movies; */
        alert("result:"+JSON.stringify(responseJson))
        this.setState({
            dataSource:this.state.dataSource.cloneWithRows(responseJson)
        })
     }).catch((error) => {
         console.error(error);
     });
Lavaraju
la source
-1

Pour les appareils Android, accédez au dossier racine de votre projet et exécutez la commande:

adb reverse tcp:[your_own_server_port] tcp:[your_own_server_port]

par exemple, adb reverse tcp:8088 tcp:8088

Cela permettra à votre appareil physique (par exemple, téléphone Android) d'écouter le serveur localhost exécuté sur votre machine de développement (c'est-à-dire votre ordinateur) à l'adresse http: // localhost: [your_own_server_port] .

Après cela, vous pouvez directement utiliser http:localhost:[your_port] /your_apidans votre fetch(appel react-native ).

Preetam Keshari Nahak
la source
-1

Pour Android, ajoutez android: networkSecurityConfig = "@ xml / network_security_config" à la balise d'application dans AndroidManifest.xml, comme ceci:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest ... >
        <application android:networkSecurityConfig="@xml/network_security_config"
                        ... >
            ...
        </application>
    </manifest>

Contenu du fichier network_security_config.xml:

<?xml version='1.0' encoding='utf-8'?>
<network-security-config>
<debug-overrides>
    <trust-anchors>
        <!-- Trust user added CAs while debuggable only -->
        <certificates src="user" />
    </trust-anchors>
</debug-overrides>

<!-- let application to use http request -->
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
xyz
la source
pourriez-vous s'il vous plaît élaborer et expliquer en détail? Je suis juste curieux de savoir comment cela fonctionne?
ganeshdeshmukh
J'ai modifié le commentaire, j'espère que cela vous aidera
xyz
-5

Exemple:

return fetch('http://<your ip>')
  .then((response) => response.json())
  .then((responseJson) => {
    console.log(responseJson)
  })
  .catch((error) => {
    console.error(error);
  });
Akhila Antony
la source