programing tip

네이티브 fetch () 네트워크 요청 실패

itbloger 2020. 7. 15. 07:50
반응형

네이티브 fetch () 네트워크 요청 실패


react-native init(RN 버전 0.29.1)을 사용하여 새로운 프로젝트를 만들고 렌더 메소드에 공개 페이스 북 데모 영화 API에 가져 오기를 넣으면을 던집니다 Network Request Failed. 매우 쓸모없는 스택 추적이 있으며 크롬 콘솔에서 네트워크 요청을 디버깅 할 수 없습니다. 내가 보내는 패치는 다음과 같습니다.

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

여기서 문제는 iOS가 기본적으로 HTTP 요청을 허용하지 않고 HTTPS 만 허용한다는 것입니다. HTTP 요청을 활성화하려면 이것을 다음에 추가하십시오 info.plist.

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

http에 모든 도메인을 허용하지 않는 것이 좋습니다. 필요한 도메인 만 예외로 설정하십시오.

출처 : iOS 9 및 OSX 10.11에서 앱 전송 보안 예외 구성

앱의 info.plist 파일에 다음을 추가하십시오.

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

나는 localhost주소를 사용하고 있었는데, 분명히 틀렸다. 에뮬레이터가있는 네트워크에서 서버의 IP 주소로 교체 한 후에 완벽하게 작동했습니다.

편집하다

Android Emulator에서 개발 시스템의 주소는 10.0.2.2입니다. 자세한 설명은 여기

Genymotion의 경우 주소는 10.0.3.2입니다. 더 많은 정보는 여기에


서버 구성에 문제가있을 수 있습니다.

Android 7.0에는 여기에 설명 된 버그가 있습니다 . Vicky Chijwani가 제안한 해결책 :

타원 곡선 프라임 256v1을 사용하도록 서버를 구성하십시오. 예를 들어 Nginx 1.10에서는 ssl_ecdh_curve prime256v1;


React Native Docs가 이에 대한 답을 제공합니다.

Apple has blocked implicit cleartext HTTP resource loading. So we need to add the following our project's Info.plist (or equivalent) file.

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


For us it was because we were uploading a file and the RN filePicker did not give the proper mime type. It just gave us 'image' as the type. We needed to change it to 'image/jpg' to get the fetch to work.

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

I got the same issue on Android but I managed to find a solution for it. Android is blocking cleartext traffic (non-https-requests) since API Level 28 by default. However, react-native adds a network-security-config to the debug version (android/app/src/debug/res/xml/react_native_config.xml) which defines some domains (localhost, and the host IPs for AVD / Genymotion), which can be used without SSL in dev mode. You can add your domain there to allow http requests.

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

For Android, you may have missed to add permission in AndroidManifest.xml Need to add the following permission.

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

I have similar problem. In my case requests to localhost was working and suddenly stopped. It turn out that the problem was that I was turn off my wifi on my android phone.


I was having this problem for Android-

URL- localhost/authToken.json - didn't work :(

URL- 10.106.105.103/authToken.json - didn't work :(

URL- http://10.106.105.103/authToken.json - worked :) :D

Note- Use ifconfig on Linux or ipconfig on Windows to find machine IpAddress


For Android user:

  1. Replace localhosts to a Lan IP addresses because when you run the project on an Android device, localhost is pointing to the Android device, instead of your computer, example: change http://localost to http://192.168.1.123

  2. If your request URL is HTTPS and your Android device is under a proxy, assume you have installed User-added CA(like burp suite's CA or Charles's CA) in your Android device, make sure your Android version is below Nougat(7.0), because: Changes to Trusted Certificate Authorities in Android Nougat

    User-added CAs
    Protection of all application data is a key goal of the Android application sandbox. Android Nougat changes how applications interact with user- and admin-supplied CAs. By default, apps that target API level 24 will—by design—not honor such CAs unless the app explicitly opts in. This safe-by-default setting reduces application attack surface and encourages consistent handling of network and file-based application data.


I came across the same issue on Android Emulator, where I tried to access an external HTTPS URL with a valid certificate. But fetching that URL in react-native failed

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

1) To find out the exact error in the logs, I first enabled 'Debug JS Remotely' using Cmd + M on the app

2) The error reported was

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

3) I added the URL's valid certificate using this method -> STEP 2

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

This certificate gets added to the User tab.

4) Add the attribute android:networkSecurityConfig attribute to AndroidManifest.xml

Add a Network Security Configuration file 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>

This should work and give you an expected response.


This worked for me, android uses a special type of IP address 10.0.2.2 then port number

import { Platform } from 'react-native';

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

if you use docker for the REST api, a working case for me was to replace hostname: http://demo.test/api with the machine ip address: http://x.x.x.x/api . You can get the IP from checking what ipv4 you have on your wireless network. You should have also the wifi from phone on.


You should handle the error case in .then for fetch API.

For example:

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

Just you have Changes in 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);
     });

For android, add android:networkSecurityConfig="@xml/network_security_config" in tag

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>

<base-config cleartextTrafficPermitted="true" />
</network-security-config>

For Android devices, go to your project root folder and run the command:

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

e.g., adb reverse tcp:8088 tcp:8088

This will make your physical device(i.e. Android phone) listen to the localhost server running on your development machine (i.e. your computer) on address http://localhost:[your_own_server_port].

After that, you can directly use http:localhost:[your_port] /your_api in your react-native fetch() call.


Example:

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

참고URL : https://stackoverflow.com/questions/38418998/react-native-fetch-network-request-failed

반응형