React Native在安卓虚拟机上运行时,使用fetch或者axios向后端索取数据时候提示:【TypeError: Network request failed】或者类似提示
解决React Native无法利用fetch或者axios向部分端口或者域名发起请求的问题
问题
如标题,我想向我的后端发送一个请求,但是提示网络错误。但是并不是对所有的url(不同域名或者ip地址)都是提示错误,有部分url能够成功获取数据。已知使用的后台都是正确可用的。
axios
.get('http://xxx.xxx.xxx.xxx:3000/api/...', {
headers: {
Accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Content-Type': 'application/json',
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/',
'Access-Control-Allow-Origin': '*', // 允许跨域
},
})
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
问题分析
看了很多中文答案,但是都不凑效,那么就只有对问题进行分析了
- 首先无论是控制台还是flipper这样的debug工具,都未详细说明为什么网络请求失败,所以不清除具体缘由。
- 利用flipper的网络检测工具,发现这些错误请求压根就没有发送出去,网络请求一栏中全部都是空白,所以应该是RN把这个请求拦截了,与后端服务器无关。
- http和https测试后均表示可以成功发送部分请求,说明错误与协议无关。
- 无论使用ip地址还是域名作为url,都有成功发送请求的实例,说明与用ip地址或者域名是无关的。
- 当然fetch和axios都同时成功或者失败,那么自然说明与请求的方法无关。
- 什么请求头啊、跨域什么都也弄了的,所以与这个无关
这就很神奇了,太神奇了!这是个什么缘由。只有从stackoverflow之类的地方看看国外大神了,他们也说到了一个可能原因;
- ios中仅支持https,不过android没有这个问题。过!
- 没有设置<uses-permission android:name="android.permission.INTERNET" />
- 没有设置form类型
- 等等都没用实际作用的
后面看到github相关issue发现可能与ca证书有关,我的后端没有备案只用使用ip地址访问,同时为了安全我又申请了zeroSSL的相关证书,可能就是与ca证书不被这个安卓识别的原因,但是链接被拒绝的原因。
解决问题
没有证书,我就给它证书。参考相关内容(需要翻墙)对ca进行设置。
1.首先在android/app/src/main/AndroidManifest.xml中进行修改
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:usesCleartextTraffic="true"
<-- 增加下面一行,标志出安全文件的xml位置 -->
android:networkSecurityConfig="@xml/network_security_config"
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2.然后android/app/src/main/res/xml/network_security_config.xml(没有就创建一个)中写下ca的相关安全设置
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- 信任系统默认的CAs -->
<!-- <certificates src="system" />-->
<!-- 信任用户安装的CAs -->
<certificates src="@raw/certificate" />
</trust-anchors>
</base-config>
</network-security-config>
3.然后进入到android/app/src/main/res/raw文件夹(没有就创建),把目标服务器的certificate.pem或者certificate.crt证书放到这个文件夹
4.最后npm run android命令重新构建一下就好了。
当然上述的文件夹啊、文件位置什么的都可以自己决定,然后就能解决问题了!
参考
参考c网络安全配置 | App quality | Android Developers
javascript - React Native fetch() Network Request Failed - Stack OverflowHTTP Fetch fails with "TypeError: Network request failed" => Resolved · Issue #32931 · facebook/react-native · GitHub
HTTP Fetch fails with "TypeError: Network request failed" => Resolved · Issue #32931 · facebook/react-native · GitHub
另一个小问题
开发过程中需要访问localhost:3000后端,但是也会提示上面类似错误,但是实际上是因为虚拟机与本地电脑桥接问题
解决方案如下
- 利用"adb reverse tcp:3000 tcp:3000",将两个端口映射一下
- 再就是比较简单的,用10.0.2.2这个ip地址替代localhost就好了
更多推荐
所有评论(0)