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.