HTTP Fetch fails with "TypeError: Network request failed" => Resolved
See original GitHub issueDescription
There are 83 issues opened and unanswered about network requests failing with this generic error. The main causes of the pain are:
- Not getting an answer from the team
- The exception is far too generic and does not suggest the origin of the problem
Problem description
Using fetch
to get/post on a HTTPS web server which is using a valid and trusted but not public CA.
- Using Chrome and other apps the requests are always successful and without certificate problems
Sample code in react native:
static async Post(): Promise<string> {
let srv = "my.domain.com";
let port = 5101;
let device = "abcd";
let url = `https://${srv}:${port}/Do/Something?devicename=${device}`;
try {
let response = await fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-type':'application/json'
},
body: JSON.stringify({
key: 'value',
})
});
if(response.status !== 200) throw new Error(`Can't open ${srv} for ${device} with status ${response.status}`);
return response.json();
}
catch(e) {
console.log(e);
throw(e);
}
}
Solution
Due to Android restrictions, a network_security_config
configuration must be added to the application. It is an xml file that can be added by following these steps:
- Edit the
android/app/src/main/AndroidManifest.xml
- Add the
android:networkSecurityConfig="@xml/network_security_config"
to the<application />
tag - Create the folder
android/app/src/main/res/xml
and inside a file callednetwork_security_config.xml
- If you don’t want to install the CA in the Android certificates, add the folder
android/app/src/main/res/raw
Variant 1: using the certificates added manually to Android.
In this case the CA must be visible in the User Certificates in the Android Settings. Try using them by opening a website that uses those certificates in Chrome to verify they are valid and correctly installed.
Content of the network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<!-- Localhost config is NEEDED from react-native for the bundling to work -->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">127.0.0.1</domain>
<domain includeSubdomains="true">10.0.0.1</domain>
<domain includeSubdomains="true">localhost</domain>
</domain-config>
<domain includeSubdomains="true">my.domain.com</domain>
<trust-anchors>
<certificates src="user"/>
<certificates src="system"/>
</trust-anchors>
</domain-config>
</network-security-config>
The <certificates src="user"/>
is the one giving access to the certificates installed manually.
Variant 2: using a certificate bundled with the app
You should export (using ssl) a pem certificate containing just the public key, naming it “ca” (no extension). Copy the certificate in the raw
folder
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<!-- Localhost config is NEEDED from react-native for the bundling to work -->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">127.0.0.1</domain>
<domain includeSubdomains="true">10.0.0.1</domain>
<domain includeSubdomains="true">localhost</domain>
</domain-config>
<domain includeSubdomains="true">my.domain.com</domain>
<trust-anchors>
<certificates src="@raw/ca"/>
<certificates src="system"/>
</trust-anchors>
</domain-config>
</network-security-config>
Important note (added on June 22, 2022)
The local traffic (with the packager) must be unencrypted. For this reason the <domain-config />
must contain the clearTrafficPermitted=true
.
It is also important adding the ip addresses used from react-native when debugging otherwise the application will crash because of the android:networkSecurityConfig="@xml/network_security_config"
attribute. If you see the app crashing, take not of the ip used internally from react native and add it/them to this list. For example:
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">127.0.0.1</domain>
<domain includeSubdomains="true">10.0.0.1</domain>
<domain includeSubdomains="true">10.0.1.1</domain>
<domain includeSubdomains="true">10.0.2.2</domain>
<domain includeSubdomains="true">localhost</domain>
</domain-config>
Requested fix: please never throw exceptions with a generic message, they are only a huge pain.
Version
0.67.0
Output of npx react-native info
info Fetching system and libraries information… System: OS: Windows 10 10.0.19044 CPU: (8) x64 Intel® Core™ i7-6700 CPU @ 3.40GHz Memory: 8.20 GB / 31.93 GB Binaries: Node: 16.13.0 - C:\Program Files\nodejs\node.EXE Yarn: 1.22.4 - C:\Program Files (x86)\Yarn\bin\yarn.CMD npm: 8.1.3 - C:\Program Files\nodejs\npm.CMD Watchman: Not Found SDKs: Android SDK: API Levels: 19, 23, 25, 26, 27, 28, 29, 30 Build Tools: 19.1.0, 21.1.2, 22.0.1, 23.0.1, 23.0.3, 26.0.2, 27.0.0, 28.0.0, 28.0.3, 29.0.2, 30.0.2 System Images: android-27 | Google APIs Intel x86 Atom, android-27 | Google Play Intel x86 Atom Android NDK: 22.1.7171670 Windows SDK: AllowDevelopmentWithoutDevLicense: Enabled AllowAllTrustedApps: Enabled Versions: 10.0.10586.0, 10.0.14393.0, 10.0.15063.0, 10.0.16299.0, 10.0.17134.0, 10.0.17763.0, 10.0.18362.0, 10.0.19041.0 IDEs: Android Studio: Version 2020.3.0.0 AI-203.7717.56.2031.7935034 Visual Studio: 17.1.32104.313 (Visual Studio Enterprise 2022), 16.11.32002.261 (Visual Studio Enterprise 2019) Languages: Java: 1.8.0_302 npmPackages: @react-native-community/cli: Not Found react: 17.0.2 => 17.0.2 react-native: 0.66.4 => 0.66.4 react-native-windows: Not Found npmGlobalPackages: react-native: Not Found
Steps to reproduce
Use the above code to make an HTTPS request to a website protected with certificates that are not public. They will not succeed with a generic exception (as for the issue title)
Repeat the request to a public website and it will succeed. The issue is the exception being too generic.
Snack, code example, screenshot, or link to a repository
No response
Issue Analytics
- State:
- Created 2 years ago
- Reactions:26
- Comments:20 (1 by maintainers)
Top GitHub Comments
It is an habit in this repo to ignore important issues (not only this one) for a very long time. I start believing RN is not that worthy to invest in.
It looks like the underlying okhttp library has quite good error detection and reporting. Somehow though, either the react-native networking layer, or the whatwg-fetch doesn’t capture that!