React Native fetch() 网络请求失败

React Native fetch() Network Request Failed

当我使用 react-native init(RN 版本 0.29.1)创建一个全新的项目并将提取方法放入 public facebook 演示电影 API 时,它抛出 Network Request Failed。有一个非常无用的堆栈跟踪,我无法在 chrome 控制台中调试网络请求。这是我要发送的提取:

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。 仅对必要的域进行例外处理。

来源:Configuring App Transport Security Exceptions in iOS 9 and 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>

只是你在 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);
     });

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

对于 Android,您可能错过了在 AndroidManifest.xml 中添加权限 需要添加以下权限。

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

问题可能出在服务器配置上。

Android 7.0 有一个错误 described here。 Vicky Chijwani 提出的解决方法:

Configure your server to use the elliptic curve prime256v1. For example, in Nginx 1.10 you do this by setting ssl_ecdh_curve prime256v1;

我在地址中使用 localhost,这显然是错误的。将其替换为服务器的 IP 地址(在模拟器所在的网络中)后,它完美运行。

编辑

在AndroidEmulator中,开发机地址为10.0.2.2。更多解释 here

对于 Genymotion,地址是 10.0.3.2。更多信息 here

我有类似的问题。 在我的例子中,对 localhost 的请求正在工作,但突然停止了。 原来问题是我关闭了 android phone.

上的 wifi

我在 Android-

时遇到了这个问题

URL- localhost/authToken.json - 没用 :(

URL- 10.106.105.103/authToken.json - 没用 :(

URL- http://10.106.105.103/authToken.json - 有效:) :D

注意 - 在 Linux 上使用 ifconfig 或在 Windows 上使用 ipconfig 来查找机器 IpAddress

对我们来说,这是因为我们正在上传文件,而 RN filePicker 没有提供正确的 mime 类型。它只是给了我们 'image' 作为类型。我们需要将其更改为 'image/jpg' 才能使提取正常工作。

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

Android 用户:

  1. localhosts 替换为局域网 IP 地址,因为当您 运行 项目在 Android 设备上时,localhost 指向 Android 设备,而不是您的计算机,例如:将 http://localost 更改为 http://192.168.1.123

  2. 如果你的请求 URL 是 HTTPS 并且你的 Android 设备在代理下,假设你已经在你的 Android 设备,请确保您的 Android 版本低于 Nougat(7.0),因为:AndroidNougat 中受信任证书颁发机构的更改

    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.

对于 Android 设备,转到项目根文件夹并 运行 命令:

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

例如,adb reverse tcp:8088 tcp:8088

这将使您的物理设备(即 Android phone)在您的开发计算机(即您的计算机)地址 http://localhost:[your_own_server_port] 上侦听本地主机服务器 运行ning ].

之后,你可以直接在你的react-native fetch()调用中使用http:localhost:[your_port] /your_api

这对我有用,android 使用特殊类型的 IP 地址 10.0.2.2 然后端口号

import { Platform } from 'react-native';

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

如果您将 docker 用于 REST api,我的一个工作案例是将主机名:http://demo.test/api 替换为机器 IP 地址:http://x.x.x.x/api。您可以通过检查无线网络上的 ipv4 来获取 IP。你应该也有从 phone 开始的 wifi。

我在 Android 上遇到了同样的问题,但我设法找到了解决方案。 Android 自 API 级别 28 默认情况下阻止明文流量(非 https 请求)。但是,react-native 在调试版本 (android/app/src/debug/res/xml/react_native_config.xml) 中添加了一个网络安全配置,它定义了一些域(localhost,以及 AVD / Genymotion 的主机 IP),在开发模式下可以在没有 SSL 的情况下使用。 您可以在那里添加您的域以允许 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>

我在 Android 模拟器上遇到了同样的问题,我在其中尝试使用有效证书访问外部 HTTPS URL。但是在 react-native 中获取 URL 失败

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

1) 为了找出日志中的确切错误,我首先在应用程序上使用 Cmd + M 启用 'Debug JS Remotely'

2) 报告的错误是

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

3) 我使用此方法添加了 URL 的有效证书 -> 步骤 2

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

此证书已添加到“用户”选项卡。

4) 添加属性android:networkSecurityConfig属性到AndroidManifest.xml

添加网络安全配置文件 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>

这应该会起作用并给您一个预期的响应。

您应该在 .then 中处理错误情况以获取 API。

例如:

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

对于 android,将 android:networkSecurityConfig="@xml/network_security_config" 添加到 AndroidManifest.xml 中的应用程序标记,如下所示:

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

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>

由于 "http",我在 Android 9 上遇到了同样的问题,只需添加 android:usesCleartextTraffic="true"[ 即可解决问题=19=]在 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>

  1. 在AndroidManifest.xml中添加android:usesCleartextTraffic="true"行。

  2. 从您的 android 文件夹中删除所有调试文件夹。

通过 运行在 0.0.0.0 上设置 mock-server
注意:当您使用 json-server.

运行 连接另一台服务器时,这在 Expo 上有效


另一种方法是 运行 0.0.0.0 上的模拟服务器,而不是本地主机或 127.0.0.1。

这使得模拟服务器可以在 LAN 上访问,并且因为 Expo 需要开发机器和移动 运行将 Expo 应用程序连接到同一网络上,模拟服务器也可以访问。

使用json-server

时可以通过以下命令实现

json-server --host 0.0.0.0 --port 8000 ./db.json --watch

访问此 link 了解更多信息。

这不是答案,而是选项。 我切换到 https://github.com/joltup/rn-fetch-blob 它适用于 form-data 和文件

解决方法是简单更新 nodejs 版本 14 或更高

在我的例子中,Android 模拟器没有连接到 Wi-Fi。

看这里

在我的例子中,我有 https url 但是获取 return 网络请求失败错误所以我只是将正文字符串化并且它工作起来很有趣

fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    firstParam: 'yourValue',
    secondParam: 'yourOtherValue'
  })
});

如果您使用本地主机,只需更改它:

来自 :http://localhost:3030 至:http://10.0.2.2:3030

对我来说...我已经 https...我将 'Content-type': 'application/json' 添加到 headers

后问题就消失了
headers: {
  Authorization: token,
  'Content-type': 'application/json',
  /** rest of headers... */
}

平台: Android

HTTP 不再被允许。请使用HTTPS

从 Android API 28 和 iOS 9 开始,这些平台默认禁用不安全的 HTTP 连接。

"dependencies": {"react": "17.0.2","react-native": "0.66.1"}, 我在使用 Android 模拟器 .

时遇到了这个问题
  1. 在AndroidManifest.xml

    里面加入这几行代码
     <application
      ....
      ....
     android:usesCleartextTraffic="true">
    
  2. 然后,尝试运行你的代码在一个真正的物理设备,而不是模拟器,
    在物理设备上 运行 - 连接你的 USB 并尝试 运行 npx react-native 运行-android

只需添加

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

    <application
      android:usesCleartextTraffic="true"

在您的 AndroidManifest.xml 中,然后将 fetch URL 域 (localhost) 替换为您的 IP 地址,

const dataRaw = await fetch('http://192.168.8.102:4000');

就我而言,https 请求也显示相同。

重新安装应用程序解决了。