React Native fetch () Żądanie sieciowe nie powiodło się


146

Kiedy tworzę zupełnie nowy projekt przy użyciu react-native init(RN wersja 0.29.1) i umieszczam pobieranie w metodzie renderowania do publicznego interfejsu API filmu demonstracyjnego na Facebooku, generuje plik Network Request Failed. Istnieje bardzo bezużyteczny ślad stosu i nie mogę debugować żądań sieciowych w konsoli Chrome. Oto pobieranie, które wysyłam:

fetch('http://facebook.github.io/react-native/movies.json')
      .then((response) => response.json())
      .then((responseJson) => {
        return responseJson.movies;
      })
      .catch((error) => {
        console.error(error);
      });

1
Nie jestem pewny. Używam symulatora iOS i myślałem, że korzysta z połączenia internetowego mojego komputera
— Alek Hurst

Spróbuj ręcznie załadować symulator i otworzyć adres URL w safari
— FuzzyTree

5
http-> https(jeśli to możliwe) najprawdopodobniej rozwiąże twój problem
— Nick Zuber

1
192.168.1.25:3000ifconfigrails server --binging=192.168.1.25 --port=3000
— Fabrizio Bertoglio

1
Tak, próbowałem wszystkich. Nic nie działało dla mnie
— Vigneswaran A

Odpowiedzi:


140

Problem polega na tym, że iOS domyślnie nie zezwala na żądania HTTP, tylko HTTPS. Jeśli chcesz włączyć żądania HTTP, dodaj to do info.plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

2
Ta odpowiedź zadziałała dla mnie. Dla innych nowych użytkowników React Native ten plik (info.plist) może być również edytowany przez xcode: stackoverflow.com/a/38219454/1299792
— Marklar

86
a co z androidem? Mam ten sam problem również w Androidzie.
— Vijay Sharma

16
Dokładnie. Czy ktoś ma odpowiedź na Androida?
— Zach Cook

1
kiedy umieszczam to na ios / build / info.plist i uruchamiam: react-native run-ios Ios / build / info.plist jest nadpisywany i kończę moje zmiany Co mam zrobić?
— Jorge Wander Santana Ureña

1
@ JorgeWanderSantanaUreña modified [your_project_folder_name] / ios / [your_project_folder_name] / In‌ fo.plist
— kgosse

58

Nie zaleca się zezwalania wszystkim domenom na http. Zrób wyjątek tylko dla niezbędnych domen.

Źródło: Konfigurowanie wyjątków zabezpieczeń transportu aplikacji w systemach iOS 9 i OSX 10.11

Dodaj następujące informacje do pliku info.plist swojej aplikacji:

<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>

27
a co z androidem?
— arisalexis

3
Wygląda na to, że w wielu katalogach mojej aplikacji React Native znajduje się wiele plików info.plist. Masz pomysł, który folder zawiera poprawny plik do zmiany?
— Marklar

2
@Marklar [your_project_folder_name] / ios / [your_project_folder_name] /Info.plist
— Stich

jeśli używam mojego localhost tutaj: <key> yourserver.com </key>, kiedy będę gotowy do publikacji, będę musiał to zmienić, prawda?
— Anayo Oleru

36

Używałem localhostadresu, co było oczywiście błędne. Po zastąpieniu go adresem IP serwera (w sieci, w której znajduje się emulator) działało idealnie.

Edytować

W emulatorze systemu Android adres maszyny deweloperskiej to 10.0.2.2. Więcej wyjaśnień tutaj

W przypadku Genymotion adres to 10.0.3.2. Więcej informacji tutaj


4
Dziękuję Ci. Prawdopodobnie jedyna odpowiedź, jaką widziałem, działa na Androida. Użyłem adresu IP mojej sieci i działa. np.http://<Network IP emulator connects to>:<port where API is served>/api/tasks
— Brandon Benefield

1
Nie zapomnij o „http: //”, bo inaczej nie zadziała ... zastanawiałem się, dlaczego będzie działać na listonoszach, ale nie przy pobieraniu
— Moucheg

@Mahmoodvcs Twoja odpowiedź bardzo mi pomogła, bardzo dziękuję, używam emulatora Androida.
— Pena Pintada

14

Dla nas było to spowodowane tym, że ładowaliśmy plik, a RN filePicker nie podał odpowiedniego typu MIME. To tylko dało nam „obraz” jako typ. Musieliśmy zmienić to na „image / jpg”, aby pobieranie działało.

form.append(uploadFileName, {
  uri : localImage.full,
  type: 'image/jpeg',
  name: uploadFileName
 })

@JohhanSantana Prawdopodobnie mógłbyś spojrzeć na surowe dane obrazu i pobrać je od samego początku, ale natywny selektor reakcji właśnie wrócił do mnie „obraz”.
— NickJ

10

React Native Docs daje odpowiedź na to pytanie.

Firma Apple zablokowała niejawne ładowanie zasobów HTTP w postaci zwykłego tekstu. Musimy więc dodać następujący plik Info.plist naszego projektu (lub odpowiednik).

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

React Native Docs -> Integration with Existing Apps -> Test your Integration -> Add App Transport Security


9

Problem może dotyczyć konfiguracji serwera.

Android 7.0 ma opisany tutaj błąd . Obejście zaproponowane przez Vicky Chijwani:

Skonfiguruj serwer tak, aby używał krzywej eliptycznej prime256v1. Na przykład w Nginx 1.10 można to zrobić, ustawiając ssl_ecdh_curve prime256v1;


7

Mam ten sam problem na Androidzie, ale udało mi się znaleźć rozwiązanie. Android blokuje ruch w postaci zwykłego tekstu (żądania inne niż HTTPS) od poziomu API 28 domyślnie. Jednakże, react-native dodaje do wersji debugowania ( android/app/src/debug/res/xml/react_native_config.xml) parametr network-security-config, który definiuje niektóre domeny (localhost i adresy IP hosta dla AVD / Genymotion), które mogą być używane bez SSL w trybie deweloperskim. Możesz tam dodać swoją domenę, aby zezwalać na żądania 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>

To zadziałało dla mnie z
— responsem

7

Mam ten sam problem w Androidzie 9 z powodu „http” i problem został rozwiązany przez dodanie androida: usesCleartextTraffic = „true” w 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>


2
Dzięki, dla mnie to też zadziałało. Dzieje się tak, ponieważ Android nie obsługuje już domyślnie HTTP w API 28.
— Gui Herzog,

5

Natknąłem się na ten sam problem na emulatorze Androida, gdzie próbowałem uzyskać dostęp do zewnętrznego adresu URL HTTPS z ważnym certyfikatem. Ale pobranie tego adresu URL w natywnej wersji reaktywnej nie powiodło się

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

1) Aby znaleźć dokładny błąd w dziennikach, najpierw włączyłem `` Debuguj JS zdalnie '' za pomocą Cmd + M w aplikacji

2) Zgłoszony błąd to

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

3) Dodałem ważny certyfikat adresu URL tą metodą -> KROK 2

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

Ten certyfikat zostanie dodany do karty Użytkownik.

4) Dodaj atrybut android:networkSecurityConfigatrybutu do AndroidManifest.xml

Dodaj plik konfiguracji zabezpieczeń sieci 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>

To powinno zadziałać i dać oczekiwaną odpowiedź.


Musiałem tylko zrobić krok 4, aby działać. Dzięki!
— Bruno Serrano

4

Miałem ten problem na Androida -

URL- localhost / authToken.json - nie działa :(

URL- 10.106.105.103/authToken.json - nie działa :(

URL- http://10.106.105.103/authToken.json - działało :): D

Uwaga - użyj ifconfigw systemie Linux lub ipconfigWindows, aby znaleźć adres IpAddress komputera


4

Dla użytkownika Androida:

  1. Zamień localhosts na adresy IP sieci LAN, ponieważ po uruchomieniu projektu na urządzeniu z systemem Android localhost wskazuje urządzenie z systemem Android, a nie komputer, na przykład: zmień http://localostnahttp://192.168.1.123

  2. Jeśli adres URL Twojego żądania to HTTPS, a Twoje urządzenie z Androidem jest na serwerze proxy, załóżmy, że zainstalowałeś CA dodany przez użytkownika (np. CA Burp Suite lub Charles CA) na swoim urządzeniu z Androidem, upewnij się, że Twoja wersja Androida jest niższa niż Nougat (7.0) , ponieważ : Zmiany w zaufanych urzędach certyfikacji w Android Nougat

    Urzędy certyfikacji dodane przez użytkowników
    Ochrona wszystkich danych aplikacji jest kluczowym celem piaskownicy aplikacji na Androida. Android Nougat zmienia sposób interakcji aplikacji z urzędami certyfikacji dostarczonymi przez użytkowników i administratorów. Domyślnie aplikacje, które są ukierunkowane na 24 poziom interfejsu API - zgodnie z projektem - nie będą honorować takich urzędów certyfikacji, chyba że aplikacja wyraźnie się na to zgodzi. To domyślne ustawienie domyślne ogranicza powierzchnię ataków aplikacji i zachęca do spójnej obsługi danych aplikacji sieciowych i plikowych.


3

W przypadku systemu Android mógł brakować dodawania uprawnień w pliku AndroidManifest.xml Należy dodać następujące uprawnienie.

<uses-permission android:name="android.permission.INTERNET" /> 

Mam już to, mimo że otrzymuję ten błąd, czy jest jakieś inne obejście?
— masud_moni

@masud_moni znajdziesz sposób na rozwiązanie problemu? Nadal mam ten sam problem
— Rafael Rotiroti

@RafaelRotiroti tak, rozwiązałem ten problem, ale chociaż minęło trochę czasu, trudno to sobie przypomnieć, jeśli korzystałeś z pozwolenia i nadal masz problemy, podaj szczegóły. Zrobię co w mojej mocy, aby pomóc, a Ty będziesz miał innych, aby się tym
— zająć

@masud_moni dziękuję, naprawiłem ten problem używając adresu IP podanego po uruchomieniu polecenia ifconfig. AVD tworzy urządzenie wirtualne, więc używając tej samej teorii, co maszyny wirtualne, które nie są hostowane w 127.0.0.1 na moim urządzeniu. Więc używam adresu IP 192.168.xx i wszystko działa dobrze
— Rafael Rotiroti

2

Mam podobny problem. W moim przypadku żądania do localhost działały i nagle się zatrzymały. Okazało się, że problem polegał na tym, że wyłączyłem wifi na moim telefonie z Androidem.


2

To zadziałało dla mnie, Android używa specjalnego typu adresu IP 10.0.2.2, a następnie numeru portu

import { Platform } from 'react-native';

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

1

jeśli używasz docker dla API REST, sprawa pracy było dla mnie, aby zastąpić nazwę hosta: http://demo.test/apiz adresem IP urządzenia: http://x.x.x.x/api. Możesz uzyskać adres IP, sprawdzając, jakie masz IPv4 w swojej sieci bezprzewodowej. Powinieneś także mieć włączone wifi z telefonu.


1

Powinieneś obsłużyć przypadek błędu w., A następnie pobrać interfejs API.

Na przykład:

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;
});

0
  1. Dodaj android:usesCleartextTraffic="true"wiersz w pliku AndroidManifest.xml.

  2. Usuń cały folder debugowania z folderu Androida.


0

Możesz sobie z tym poradzić, używając tego:

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,
      });
    });

-1

Po prostu masz zmiany w pobieraniu ...

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);
     });

-1

W przypadku urządzeń z systemem Android przejdź do folderu głównego projektu i uruchom polecenie:

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

na przykład, adb reverse tcp:8088 tcp:8088

Dzięki temu Twoje urządzenie fizyczne (np. Telefon z systemem Android) będzie nasłuchiwało serwera localhost działającego na komputerze deweloperskim (tj. Komputerze) pod adresem http: // localhost: [port_własnego_serwera] .

Następnie możesz bezpośrednio użyć http:localhost:[your_port] /your_apiw swoim rodzimym fetch(wywołaniu.


-1

W przypadku Androida dodaj android: networkSecurityConfig = "@ xml / network_security_config" do tagu aplikacji w AndroidManifest.xml, na przykład:

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

zawartość pliku 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>

czy mógłbyś to rozwinąć i wyjaśnić szczegółowo? Jestem po prostu ciekawy, jak to działa?
— ganeshdeshmukh

Zmodyfikowałem komentarz, mam nadzieję, że to pomoże
— xyz

-5

Przykład:

return fetch('http://<your ip>')
  .then((response) => response.json())
  .then((responseJson) => {
    console.log(responseJson)
  })
  .catch((error) => {
    console.error(error);
  });
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.