Cannot upload file from React Native: "Network request failed"? - expo

When trying to upload a selected image from my React Native project I get a nondescript error message:
Network request failed
Seems to be a common issue, but most people are just forgetting their file types or are on Android and have an issue with Flipper. Nothing that has worked for anyone I've found with the same symptoms has worked for me.
Code:
const localUri = result.uri;
const filename = localUri.split("/").pop();
const type = mime.lookup(localUri) || "image";
const formData = new FormData();
formData.append("file", { uri: localUri, name: filename, type });
try {
const file = await fetch(`${SERVER_URL}/api/upload`, {
method: "POST",
body: formData,
}).then((res) => {
console.log(res);
return res.status === 200 ? res.text() : res.json();
});
} catch (e) {
console.log(e);
}
Considerations:
Using a physical IOS device. Iphone.
Using Expo 40.0.0 with corresponding RN SDK, not ejected.
Using expo-image-picker to get image.
Using NGROK to get requests through to my localhost server from my phone.
All other requests to my server from React Native work fine, it's only when I try to uplaod a file
Image renders fine from supplied URI, so it's getting the right source.
Form Data source from above:
{ "name": "CAPS-FILE-NAME.jpg", "type": "image/jpeg", "uri": "file:///var/mobile/Containers/Data/Application/CAPS-PATHING/Library/Caches/ExponentExperienceData/project-src-pathing/ImagePicker/CAPS-FILE-NAME.jpg", }
Things tried:
Using Content-Type header: "multipart/form-data"
Using /private instead of file://
Using Postman to hit my server through NGROK, which works
Changing my Expo/RN to 38.0.0
Getting base64 -> blob -> formData, same result
Many other things I've forgotten now. If it's on Google results, I've tried it.

For anyone who gets stuck with this also, I switched to using XMLHttpRequest instead of fetch and it miraculously works now. Not sure why fetch is broken in RN, but at least there's a solution.

Related

iOS can't play uploaded audio: JS MediaRecorder -> Blob -> Django Server -> AWS s3 -> JS decodeAudioData --> "EncodingError: Decoding Failed"

Answer: shouldn't set content/mime type browser side with JS, should use native browser mimeType then convert server side (I used PyDub).
Question:
I am using Javascript MediaRecorder, Django, AWS s3 and Javascript Web Audio API to record audio files for users to share voice notes with one another. I've seen disbursed answers online about how to record and upload audio data and the issues with Safari/iOS but thought this could be a thread to bring it together and confront some of these issues.
Javascript:
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.onstop = function (e) {
var blob = new Blob(
chunks,
{
type:"audio/mp3",
}
);
var formdata = new FormData();
formdata.append('recording', blob)
var resp = await fetch(url, { // Your POST endpoint
method: 'POST',
mode: 'same-origin',
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': csrf_token,
},
body: formdata,
})
}
Django:
for k,file in request.FILES.items():
sub_path = "recordings/audio.mp3"
meta_data = {"ContentType":"audio/mp3"}
s3.upload_fileobj(file, S3_BUCKET_NAME, sub_path,ExtraArgs=meta_data)
###then some code to save the s3 URL to my database for future retrieval
Javascript:
var audio_context = new AudioContext();
document.addEventListener("#play-audio","click", function(e) {
var url = "https://docplat-bucket.s3.eu-west-3.amazonaws.com/recordings/audio.mp3"
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onload = function () {
audio_context.decodeAudioData(request.response, function (buffer) {
playSound(buffer)
});
}
request.send();
})
Results in:
"EncodingError: Decoding Failed"
Note however that using the w3 schools demo mp3 url does play the recording:
https://docplat-bucket.s3.eu-west-3.amazonaws.com/recordings/t-rex-roar.mp3
Specs:
PC (used to upload recoding): Windows 11, Chrome Version 98.0.4758.81 (Official Build) (64-bit)
Django: Version: 3.1.7
Mobile (used to play recording): iPhone X, iOS (Version 14.7.1)
Problematic url: https://docplat-bucket.s3.eu-west-3.amazonaws.com/recordings/audio.mp3
Working url: https://docplat-bucket.s3.eu-west-3.amazonaws.com/recordings/t-rex-roar.mp3
(This is my first post so please forgive me if I haven't asked this question in the ideal way :) )
When you upload the recorded Blob you set the type to 'audio/mp3'. But unless you use a custom library which patches the MediaRecorder the mimeType of the recording will be whatever the browser likes best.
As of now it's 'audio/opus' in Firefox and 'audio/webm' in Chrome.
If you define your Blob like this it should work.
var blob = new Blob(
chunks,
{
type: mediaRecorder.mimeType
}
);
You would also have to change your server side code to not use 'audio/mp3' anymore.

S3 - Video, uploaded with getSignedUrl link, does not play and is downloaded in wrong format

I am using AWS SDK in Server Side with Node.JS and having issue with uploading files as formData from client side.
On the server side I have simple route, which creates upload link, where video will be uploaded later directly from client side.
I am using S3 getSignedUrl method for generating that link with putObject, which creates PUT request for client, but causes very strange issue with formData.
Video uploaded as formData is not behaving correctly - instead of playing it S3 uploaded url downloads that video and it is also broken.
Here is simple how i configure that method on server side:
this.s3.getSignedUrl(
'putObject',
{
Bucket: '<BUCKET_NAME>',
ContentType: `${contentType}` -> video/mp4 as a rule,
Key: key,
},
(err, url) => {
if (err) {
reject(err)
} else {
resolve(url)
}
},
)
axios put request with blob is actually working, but not for formData.
axios.put(url, file, {
headers: {
'Content-Type': file.type,
},
onUploadProgress: ({ total, loaded }) => {
setProgress((loaded / total) * 100)
},
})
This is working version, but when I try to add file to formData, it is uploaded to S3, but video downloads instead of playing.
I do not have big experience in AWS, so if somebody knows how to handle that issue, I will be thankfull

Axios GET request to server - not local host

I was wondering if someone could bring some light on how GET request paths work. I am not skilled in networking so am a bit lost here.
I have a Flask app running on PythonAnywhere... I built a small app with Vue and am using Axios for send GET request to my API on server. I however found out that when I run my app on PythonAnywhere server i will get response only when I also run the flask app on my local machine. I suspect it is due to me trying to send the request to http://localhost:5000/api/random2. Is that true? What do I have to replace it with to send the request to my PythonAnywhere app?
getResults () {
const path = `http://localhost:5000/api/random2`
axios.get(path, {
params: {
p_a: this.p_a,
R_eH: this.R_eH,
a: this.a,
b: this.b
}
})
.then(response => {this.result = response.data})
.catch(error => {
console.log(error)
})
}
},
Thank you,
Jakub

Unable to upload signature to remote server using `fileTransfer` plugin in ionic but works fine in local server

I am using fileTransfer plugin to upload signature in my ionic 2 app. To capture signature I am using angular2-signaturepad.
let options: FileUploadOptions = {
fileKey: 'file',
fileName: 'Order_'+this.order_data.order_id+"_"+this.order_data.order_type+".png",
headers: {},
};
fileTransfer.upload(this.signaturePad.toDataURL(),
this.api+'php/wd_upload.php?location=signs', options)
.then((data) => {
// success
}, (err) => {
// error
});
The above code works fine in local server, and signature is uploaded successfully. But when I try to change this api to refer remote server. This file transfer failed with following error
body: "<head><title>Not Acceptable!</title></head><body><h1>Not Acceptable!</h1><p>An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.</p></body></html>"
code: 1
exception: "http://<remote_server>/php/wd_upload.php?location=signs"
http_status: 406
source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAADICAYAAABS39xVAAAYsElEQVR4Xu2dXXBVVZbHd4QmCfMyScq ...."
target: "http://<remote_server>/php/wd_upload.php?location=signs"
Please solve this problem ?
Everything worked fine when I replaced option as follow
let options: FileUploadOptions = {
fileKey: 'file',
fileName: 'Order_'+this.order_data.order_id+"_"+this.order_data.order_type+".png",
httpMethod : 'POST',
mimeType: 'image/png',
chunkedMode: false,
headers : {"Accept": "image/png"}
};

Making Network Requests through React Native

I have just started learning React Native. Built my Component and am trying to use an authenticate function written in a separate file to authenticate.
My Authenticate file looks like
var constants = require("../constants")
module.exports = function(usr,pwd){
var trailing_url = '/api/token/';
var url = constants.DOMAIN + trailing_url;
console.log("url");
return fetch(url, {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: usr,
password: pwd,
})
}).then(function(response){
return response.json();
}).then(function(json){
return json;
});
}
I am experiencing this error once i go to fetch. I am unable to make network requests to my backend in django which is running at http://127.0.0.1:8000/api/token/
I am getting the following error. Couldn't copy paste that here for some reason.
Another question I had is how to debug the code? I tried the Chrome debugger.
But its showing
Status: Waiting, press Ctrl R in simulator to reload and connect.
Tried refreshing the Simulator but didn't work.
Thanks Ashutosh for pointing that out. I didn't notice that since the emulator is a different machine, it wouldn't actually recognize localhost or 127.0.0.1
The problem was i was using the local machine's Loopback IP Address when requesting for data.