expo: TypeError: Network request failed when fetching a file:// uri
Environment
Environment:
OS: Windows 10
Node: 8.11.0
Yarn: 1.7.0
npm: 5.6.0
Watchman: Not Found
Xcode: N/A
Android Studio: Version 3.1.0.0 AI-173.4907809
Packages: (wanted => installed)
expo: ^30.0.0 => 30.0.1
react: 16.3.1 => 16.3.1
react-native: https://github.com/expo/react-native/archive/sdk-30.0.0.tar.gz => 0.55.4
App target - Standalone & Client for testing
Steps to Reproduce
- use this expo example of recording audio
- mix it with this example of uploading to firebase
Expected Behavior
fetching a file URI from the device file system should return a valid response.
Actual Behavior
I’m getting a network error exception
TypeError: Network request failed
and if I’m running with remote JS debug mode I can see this error in chrome console
Failed to load file:///data/user/0/host.exp.exponent/cache/ExperienceData/…/Audio/recording-eee85da3-7121-4273-86a7-686098180662.m4a: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
Some Code
const asyncUpload = async ()=> {
try {
const response = await fetch(recordInfo.uri);
console.log("response", response);
const blob = await response.blob();
const blob = new Blob();
upload( blob)
}catch (e) {
console.log("error fetching",e);
}
}
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 2
- Comments: 16 (2 by maintainers)
TL;DR: Replace
fetch().blob()with:Let me guide you through some code to understand the problem better:
Let’s start with
fetchfunction. It’s currently not supported natively by JSC on which JS code runs. When we use React Native, it’s being polyfilled by the framework.Pre-0.57, React Native used a regular
whatwg-fetchpolyfill, implementingfetchwithXMLHttpRequest(XMLHttpRequestpolyfill has always been implemented by RN), to enable developers to usefetch(usage, dependency definition). (whatwg-fetchhas setxhr.responseTypeby default to"blob".) React Native’sXMLHttpRequestimplementation, in turn, usesNetworkingModuleto issue the request. So, at the end,NetworkingModule.sendRequestis called.Inspecting
NetworkingModule.sendRequestmethod we can see that before any real network request is constructed, it first iterates overmUriHandlers. It’s a list of objects conforming toUriHandlerinterface, which is very simple, and as the documentation says:So if we would like to support some custom URI scheme, we would add our own
UriHandlertoNetworkingModule, nice! 👌In a basic React Native application (on Android), there is only one such custom handler, created by
BlobModule— link. As we can see from the implementation, it runs only for requests that both:http://orhttps://andblobas response type.For such requests, this handler is capable of returning a valid blob as expected. So why doesn’t it work in RN 0.57+?
This commit, which first landed in React Native 0.57 switched the default
xhr.responseTypefromblobtotext. Thus,BlobModule’sUriHandlerdoesn’t kick in, and sinceokhttpdoesn’t recognize URL offile://scheme, it throws an exception.It’s important to note that this commit doesn’t introduce a bug. In fact, it fixes a blob leak that was occurring due to
fetchrequests not releasing underlying native blobs when they’re done with it!Since we really need this blob, and can’t use
fetch(there’s no way to pass an option that would instructfetchto start withresponseType = blob) we have to constructXMLHttpRequestourselves.The following snippet creates a very basic blob promise:
In order not to leak blobs, we should also call
blob.close()when we’re done sending it. That’s why the full snippet ofasyncUploadshould look like this:Blobs in RN need to be brought into compliance with JS specs with proper native implementations. I’m not convinced they should even be called Blob currently.
See: https://github.com/facebook/react-native/issues/22681
God Damn Hero
Also got this issue.
base64 firebase upload also broken on android