网络请求失败

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

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

这里的问题是iOS默认不允许HTTP请求,只允许HTTPS。如果你想启用HTTP请求,添加到你的info.plist:

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

不建议允许http的所有域。 为必要的域做一个例外

来源:在iOS 9和OSX 10.11中配置应用程序传输安全例外

将以下内容添加到信息中。你的应用的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给出了这个问题的答案。

苹果已经阻止隐式明文HTTP资源加载。所以我们需要添加以下我们的项目的信息。Plist(或等效)文件。

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

React Native Docs ->与现有应用程序集成->测试您的集成->添加应用程序传输安全例外

对于Android,你可能错过了在AndroidManifest.xml中添加权限

.需要增加以下权限
<uses-permission android:name="android.permission.INTERNET" />

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

Android 7.0有一个bug 这里描述。Vicky Chijwani提出的解决方案:

配置您的服务器以使用椭圆曲线prime256v1。为 例如,在Nginx 1.10中,你可以通过设置ssl_ecdh_curve来实现 prime256v1; < / p >

我使用localhost作为地址,这显然是错误的。在将其替换为服务器的IP地址(在仿真器所在的网络中)后,它可以完美地工作。

编辑

在Android模拟器中,开发机器的地址是10.0.2.2。更多解释在这里

对于Genymotion,地址是10.0.3.2。更多信息在这里

我也有类似的问题。 在我的情况下,请求localhost工作,突然停止。 结果发现问题是我关掉了我安卓手机上的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. 将__abc0替换为Lan IP地址,因为当您在Android设备上运行项目时,localhost指向Android设备,而不是您的计算机,例如:将http://localost更改为http://192.168.1.123

  2. 如果您的请求URL是HTTPS,并且您的Android设备在代理下,假设您已经在您的Android设备中安装了用户添加的CA(如burp suite的CA或Charles的CA),请确保您的Android版本低于牛轧糖(7.0),因为:在Android Nougat中更改为受信任的证书颁发机构
    < p > 用户添加中科院 < br > 保护所有应用程序数据是 Android应用沙箱。Android Nougat改变了应用程序 与用户和管理员提供的ca交互。默认情况下,应用程序 根据设计,目标API级别24将不支持这样的ca,除非应用程序 明确地选择加入。这种默认安全设置减少了应用程序 攻击面和鼓励一致处理网络和 基于文件的应用数据 李< /引用> < / >

对于Android设备,进入您的项目根文件夹并运行命令:

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

例如,adb reverse tcp:8088 tcp:8088

这将使您的物理设备(即。Android手机)监听本地主机服务器运行在您的开发机器(即您的计算机)地址http://localhost (your_own_server_port):

之后,你可以直接在你的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/';

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

我在Android上也遇到了同样的问题,但我设法找到了解决方案。Android默认从API Level 28开始就屏蔽明文流量(非http请求)。然而,react-native在调试版本(android/app/src/debug/res/xml/react_native_config.xml)中添加了一个网络安全配置,它定义了一些域(localhost,以及AVD / Genymotion的主机ip),这些域可以在dev模式下使用,无需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启用了“远程调试JS”

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/

该证书被添加到User选项卡。

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

添加网络安全配置文件 res/xml/network_security_config.xml: < / p >

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

这应该工作,并给你一个预期的回应。

对于fetch API,你应该在.then中处理错误情况。

例如:

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,在AndroidManifest.xml的应用程序标签中添加android:networkSecurityConfig="@xml/network_security_config",如下所示:

    <?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>
我在Android 9上遇到了同样的问题,因为“http”,问题通过添加android: usesCleartextTraffic = " true "来解决 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上运行模拟服务器
注意:当你使用json-server运行另一个服务器时,这在Expo上有效。

另一种方法是在0.0.0.0而不是localhost或127.0.0.1上运行模拟服务器。

这使得模拟服务器可以在LAN上访问,因为Expo要求开发机器和运行Expo应用程序的移动设备在同一个网络上,所以模拟服务器也可以访问。

在使用json-server时,可以使用以下命令实现这一点

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

访问链接获取更多信息。

这不是答案,而是选项。 我切换到https://github.com/joltup/rn-fetch-blob 它工作良好的表单数据和文件

解决方案很简单,更新nodejs版本14或更高

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

看这里Android Studio - Android模拟器Wifi连接,没有互联网

在我的情况下,我有https url,但取回返回网络请求失败的错误,所以我只是stringify的身体,它的工作乐趣

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

如果你使用localhost,只需更改它:

< p >: http://localhost:3030 : http://10.0.2.2:3030 < / p >

对我来说……我已经https了…当我将'Content-type': 'application/json'添加到headers时,这个问题就消失了

headers: {
Authorization: token,
'Content-type': 'application/json',
/** rest of headers... */
}

平台:安卓

HTTP不再被允许。请使用HTTPS

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

< p > "dependencies": {"react": "17.0.2","react-native": "0.66.1"}, 我在Android模拟器.

. 0中遇到了这个问题
  1. 在AndroidManifest.xml中添加以下代码行

     <application
    ....
    ....
    android:usesCleartextTraffic="true">
    
  2. 然后,尝试在真实的物理设备中运行代码,而不是模拟器,
    要在物理设备上运行,请连接usb并尝试运行NPX react-native run-android

只需添加

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


<application
android:usesCleartextTraffic="true"

然后将获取URL域(主机)替换为你的IP地址,

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

在我的情况下,它对https请求也显示相同。

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

修复了在Android调试版本中上传文件到http而不是https时TypeError: Network request failed的问题

在react-native 0.63.2(我正在测试)或更高版本中,如果只是使用fetch将文件上传到http(而不是https)服务器,将满足TypeError: Network request failed

在这里,我使用axios@0.27.2作为运行在Android手机上的客户端,成功地将文件上传到react-native-file-server作为运行在另一个Android手机上的服务器。

客户端需要编辑JAVA和JS代码,服务器不需要编辑JAVA代码。

对于调试版本,必须在这个文件android/app/src/debug/java/com/YOUR_PACKAGE_NAME/ReactNativeFlipper.java注释43行

38      NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
39      NetworkingModule.setCustomClientBuilder(
40          new NetworkingModule.CustomClientBuilder() {
41            @Override
42            public void apply(OkHttpClient.Builder builder) {
43      //        builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
44            }
45          });
46      client.addPlugin(networkFlipperPlugin);

也许还需要在android/app/src/main/AndroidManifest.xml<application下添加android:usesCleartextTraffic="true",在我的测试中,在调试和发布版本中都没有必要。

  onFileSelected = async (file) => {
// API ref to the server side BE code `addWebServerFilter("/api/uploadtodir", new WebServerFilter()`
// https://github.com/flyskywhy/react-native-file-server/blob/1034a33dd6d8b0999705927ad78368ca1a639add/android/src/main/java/webserver/WebServer.java#L356
// could not be 'localhost' but IP address
const serverUploadApi = 'http://192.168.1.123:8080/api/uploadtodir';


// the folder on server where file will be uploaded to, could be e.g. '/storage/emulated/0/Download'
const serverFolder = '/storage/emulated/0/FileServerUpload';


const fileToUpload = {
// if want to upload and rename, it can be `name: 'foo.bar'`, but can not be 'foo'
// only if your server upload code support file name without type, on our server
// https://github.com/flyskywhy/react-native-file-server/blob/1034a33dd6d8b0999705927ad78368ca1a639add/android/src/main/java/webserver/WebServer.java#L372
// will cause java.lang.StringIndexOutOfBoundsException in substring()
name: file.name,


// type is necessary in Android, it can be 'image/jpeg' or 'foo/bar', but can not be
// 'foo', 'foo/', '/foo' or undefined, otherwise will cause `[AxiosError: Network Error]`
type: 'a/b',


uri: Platform.OS === 'android' ? file.uri : file.uri.replace('file://', ''),
};


const form = new FormData();
form.append('path', serverFolder);
form.append('uploadfile', fileToUpload);


// ref to the server side FE code `this.axios.post("/api/uploadtodir", parms, config)`
// https://github.com/flyskywhy/react-native-file-server/blob/1034a33dd6d8b0999705927ad78368ca1a639add/fileserverwebdoc/src/views/Manage.vue#L411
let res = await axios.post(serverUploadApi, form, {
headers: {
'Content-Type': 'multipart/form-data',
},
onUploadProgress: function (progressEvent) {
console.warn(progressEvent);
},
});


// ref to the server side BE code `return newFixedLengthResponse("Suss");`
// https://github.com/flyskywhy/react-native-file-server/blob/1034a33dd6d8b0999705927ad78368ca1a639add/android/src/main/java/webserver/WebServer.java#L380
if (res.data === 'Suss') {
console.warn('Upload Successful');
} else if (res.data === 'fail') {
console.warn('Upload Failed');
}
};

如果您正在连接到HTTPS网站,请检查您的模拟器的互联网连接。(在我的情况下,我使用通过USB连接手机模拟器,它的互联网是离线的)

为了找到根本问题,我使用了XMLHttpRequest而不是fetch,并且在发送请求后抛出了一个异常,并告诉实际问题HTTP_1_1_REQUIRED

显然,react本机(在我的情况下v0.59)只支持http/1.1,然后我在web服务器上禁用了http/2。

如果你的服务器是IIS,看看这个问题回答

希望这能有所帮助。

React-native Expo和Node Express后端也有同样的问题。这个问题是关于模拟器本地主机和服务器本地主机之间的冲突。您的后端服务器可能运行在127.0.0.1:8000上,但模拟器无法找到这一点。

在终端中使用命令“ipconfig”找到您的ipv4地址。例如,它将是192.138.1.40

之后,把它放入你的fetch ('http://192.138.1.40:8080/')。 同样重要的是—使用相同的主机和端口运行后端服务器。 例如,在Node Express上:

App.listen (8080, () =>console.log("服务器正在运行!")