React Native fetch() Network Request Failed for android? - react-native

When I create a brand new project using react-native init (RN version 0.52-RC) and put a fetch in the render method to the public API, it throws a Network Request Failed. There is a very useless stack trace and I can't debug network requests in the chrome console. Here is the fetch I'm sending:
fetch('https://test.online/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: this.emailId,
password: this.password
})
}).then((data) => {
return data.json();
}).then((data) => {
}).catch((err) => {
alert(err); // TypeError:Network request faild.
});

if you are using nginx server then change
from ssl_ecdh_curve secp384r1 to ssl_ecdh_curve prime256v1
in this /etc/nginx/snippets/ssl-params.conf file
see detail to check here https://community.letsencrypt.org/t/warning-android-7-0-clients-not-browsers-can-only-use-curve-prime256v1/23212

can you post your request code snippet? what simulator are you using Android or IOS? Generally, IOS/Android doesn't allow you to make http requests by default you have to enable them in your info.plist( for IOS )

Related

Android: Network Request Failed when trying to upload image with fetch

I'm trying to upload an image from storage to a restful API but I keep getting Network Request Failed on Android (which means the request doesn't even go through), haven't checked on iOS because I don't need that part yet. API is already working and has been tested with Postman.
The React Native code is:
body.append('vehicles',{
resource_id: 2,
resource: 'vehicles',
cat_file_id: fileId,
active: 1,
vehicles: photo, //<- photo value below
name: 'vehicles',
type: 'image/jpeg'
})
fetch(`${BASE_URL}/files`, {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
Accept: "*/*",
Authorization: 'Bearer '+auth
},
body: body
}).then(response => response.json())
.then(response => {
console.log('IMAGE RESPONSE', response)
})
.catch(error => console.log('ERROR', error))
The photo value looks like file:///storage/emulated/0/DCIM/...
The response:
ERROR TypeError: Network request failed
at XMLHttpRequest.xhr.onerror (fetch.umd.js:473)
at XMLHttpRequest.dispatchEvent (event-target-shim.js:818)
at XMLHttpRequest.setReadyState (XMLHttpRequest.js:574)
at XMLHttpRequest.__didCompleteResponse (XMLHttpRequest.js:388)
at XMLHttpRequest.js:501
at RCTDeviceEventEmitter.emit (EventEmitter.js:189)
at MessageQueue.__callFunction (MessageQueue.js:436)
at MessageQueue.js:111
at MessageQueue.__guard (MessageQueue.js:384)
at MessageQueue.callFunctionReturnFlushedQueue (MessageQueue.js:110)
On Postman the request looks something like this:
Already tried:
Removing Accept header
Changing Accept value to 'application/json'
Removing file:// from the image url
Added android:usesCleartextTraffic="true" to the manifest
Already checked:
No values are null or undefined
There is a working internet connection, all other network requests on the app are working fine
The Auth is correct
React Native version is 0.61.5
I found one missing line in your code let formData = new FormData();. but not sure is that the exact issue here.
By the way here is a sample working code from one of my project, and I customized it with your context.
Add your authentication
replace ImageURI with image path and URL_SAVE_IMAGE endpoint url
const newImage = {
resource_id: 2,
resource: 'vehicles',
cat_file_id: 1,
active: 1,
vehicles: ImageURI,
name: "my_photo.jpg",
type: "image/jpg",
};
let formData = new FormData();
formData.append("vehicles", newImage);
return fetch(URL_SAVE_IMAGE, {
method: 'POST',
headers: {
"Content-Type": "multipart/form-data"
},
body: formData
}).then(response => response.json());
it should work!
What is your fetch(${BASE_URL}/files` backend server .. This usually happens when trying to connect to the backend api on the localhost machine.. Even if you use the IP address of the localhost, it still persists, so it is better to use online server for testing or just use ngrok(https://ngrok.com/) to serve your backend localhost via internet.
in gradle.properties change the flipper version to 0.47.0
try with Xhr, it's working as expected!
const URL = "ANY_SERVER/upload/image"
const xhr = new XMLHttpRequest();
xhr.open('POST', url); // the address really doesnt matter the error occures before the network request is even made.
const data = new FormData();
data.append('image', { uri: image.path, name: 'image.jpg', type: 'image/jpeg' });
xhr.send(data);
xhr.onreadystatechange = e => {
if (xhr.readyState !== 4) {
return;
}
if (xhr.status === 200) {
console.log('success', xhr.responseText);
} else {
console.log('error', xhr.responseText);
}
};
Nothing worked for me except using the Expo FileSystem uploadAsync
uploadImage = async ({ imageUri } }) => FileSystem.uploadAsync(
apiUrl,
imageUri,
{
headers: {
// Auth etc
},
uploadType: FileSystem.FileSystemUploadType.MULTIPART,
fieldName: 'files',
mimeType: 'image/png',
});
Note - imageUri in format of file:///mypath/to/image.png
Happy days!

fetch error network on react native but working on postman

I'm currently developping a react-native app. Working on the login part,
I successfully made my call on postman with the right return but when fetching through react-native android client I get absolutly no return when calling the heroku server or even a network failed error when running the server locally.
What am I doing wrong ? I got absolutly no logs back from the code under.
const payloadJson = JSON.stringify({
email: 'julien#hypecode.com',
password: 'password',
})
fetch('https://alsatoju-dev.herokuapp.com/login', {
method: 'POST',
body: payloadJson,
headers: {
Accept: '*/*',
'Content-Type': 'application/json',
},
}).then((response) => {
console.log(response)
return response.json()
})
.then((res) => console.log(res))
.catch((err) => console.log(err))

React Native fetch returns 404 but postman does 200 ok

I am integrating Spotify web api into react native application. I have problem with React Native fetch. When I call the api inside Postman, I get 200 response code but if I run it inside emulator(react native) I get 404 error code. I also wrote the fetch request inside chrome console and it works good but in react native it is not working.
The code that I am running:
let response = await fetch(`https://api.spotify.com/v1/browse/featured-playlists?locale=en_US&country=US`, {
method: 'GET',
headers: {
'Accept': 'application/json;charset=utf-8',
'Content-Type': 'application/json;charset=utf-8',
'Authorization': 'Bearer BQDT3_xtYLyIsGaqhoTM42Z-k3ijs-hFbzIG89basd7Me-kL4SUWSLgQrxWN3b13DiqU6THfr4VH4Z7klnc'
}
});
console.log("response",response.status)
I tried the following code in React Native v. 0.58.6
async componentDidMount() {
let spotifyApiUrl = "https://api.spotify.com/v1/browse/featured-playlists?locale=en_US&country=US";
let fetchSettings = {
method: 'GET',
headers: {
'Accept': 'application/json;charset=utf-8',
'Content-Type': 'application/json;charset=utf-8',
'Authorization': 'Bearer BQDT3_xtYLyIsGaqhoTM42Z-k3ijs-hFbzIG89basd7Me-kL4SUWSLgQrxWN3b13DiqU6THfr4VH4Z7klnc'
}
};
fetch(spotifyApiUrl, fetchSettings)
.then( (response) => response.json() )
.then( (responseJson) => {
console.log(JSON.stringify(responseJson));
})
.catch((error) => {
console.log(error);
});
}
With the following console output:
{"error":{"status":401,"message":"The access token expired"}}
Have you tried plugging in your actual device to see if it is an emulator issue?
Remember to forward tcp ports on adb before running "react-native run-android" if you use a real device
adb reverse tcp:8081 tcp:8081
react-native run-android

POST fails with ReadableNativeMap cannot be cast to String error

I'm working in React Native, I use PHP for backend and when I use fetch POST request I get so strange error, and I dont know why it happens. I checked the url so it works no problem, also normal fetch() is working without POST but when I try to post it happens. When I try it in local server fetch POST works.. but in server, I get this error :
ERROR : com.facebook.react.bridge.ReadableNativeMap cannot be cast to
java.lang.String
React native codes :
fetch('http://xxx/react_test1', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: inputName,
email: inputEmail,
phone: inputPhone
}),
}).then((response) => response.json())
.then((responseJson) => {
Alert.alert(responseJson);
}).catch((error) => {
alert(error);
});
Alert.alert receives an string, and what you're getting from the fetch response is internally a com.facebook.react.bridge.ReadableNativeMap object (which is what the native implementation for fetch returns).
You can try:
Alert.alert(JSON.stringify(responseJson))
If you were using iOS you'll get a completely different error:
Exception '-[_NSFrozenDictionaryM length]: unrecognized selector ...
Alert.alert only accepts string as input.
Use alert() instead to show the popup.
Example: alert("Response: ", responseJson)
Happy Coding. :)
So with fetch() in javascript you need headers: {} but when switching over to RNFetchBlob you should put the headers directly in the {}
import RNFetchBlob from "rn-fetch-blob";
const aPath = Platform.select({ ios: DocumentDir, android: DownloadDir });
const fPath = aPath + '/' + Math.floor(date.getTime() + date.getSeconds() / 2) + '.xls';
Also if you want to add body in the request then directly add it there.
For example:-
RNFetchBlob.config({
// response data will be saved to this path if it has access right.
path: fPath,
}).fetch('POST', URL, {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: token,
},
JSON.stringify(reqBody)
)
.then(res => {
console.log("response body>>>",res);
})
.catch(function (err) {
console.log(err);
});
that's all enjoy your coding...

fetch: Getting cookies from fetch response

I'm trying to implement client login using fetch on react.
I'm using passport for authentication. The reason I'm using fetch and not regular form.submit(), is because I want to be able to recieve error messages from my express server, like: "username or password is wrong".
I know that passport can send back messages using flash messages, but flash requires sessions and I would like to avoid them.
This is my code:
fetch('/login/local', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: this.state.username,
password: this.state.password,
}),
}).then(res => {
console.log(res.headers.get('set-cookie')); // undefined
console.log(document.cookie); // nope
return res.json();
}).then(json => {
if (json.success) {
this.setState({ error: '' });
this.context.router.push(json.redirect);
}
else {
this.setState({ error: json.error });
}
});
The server sends the cookies just fine, as you can see on chrome's dev tools:
But chrome doesn't set the cookies, in Application -> Cookies -> localhost:8080: "The site has no cookies".
Any idea how to make it work?
The problem turned out to be with the fetch option credentials: same-origin/include not being set.
As the fetch documentation mentions this option to be required for sending cookies on the request, it failed to mention this when reading a cookie.
So I just changed my code to be like this:
fetch('/login/local', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
credentials: 'same-origin',
body: JSON.stringify({
username: this.state.username,
password: this.state.password,
}),
}).then(res => {
return res.json();
}).then(json => {
if (json.success) {
this.setState({ error: '' });
this.context.router.push(json.redirect);
}
else {
this.setState({ error: json.error });
}
});
From Differences from jQuery section of the Fetch API on Mozilla:
fetch() won't receive cross-site cookies. You can’t establish a cross
site session using fetch(). Set-Cookie headers from other sites are
silently ignored.
fetch() won’t send cookies, unless you set the
credentials init option. Since Aug 25, 2017: The spec changed the
default credentials policy to same-origin. Firefox changed since
61.0b13.)
I spent a long time but nothing worked for me.
after trying several solutions online this one worked for me.
Hopefully it will work for you too.
{
method: "POST",
headers: {
"content-type": "API-Key",
},
credentials: "include",
}
I had to include credentials: 'include' in the fetch options:
fetch('...', {
...
credentials: 'include', // Need to add this header.
});