I'm trying to POST data with FormData to get a response, on iOS it works as expected, but on android, it always goes to the catch block, I found out the reason for that is response.json() with error: [SyntaxError: JSON Parse error: Unrecognized token '']
Here is my code:
const onAndroidSucks = () => {
setLoading(true);
let formData = new FormData();
formData.append("number", number.replace(/\s+/g, '').substring(4));
formData.append("id", userID);
formData.append("token", userToken);
fetch(ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data'
},
body: formData
}).then(response => response.json()).then(response => {
if (response.res === 'no') {
Alert.alert('ჰეჰე');
} else {
setData(response);
}
setLoading(false);
}).catch(err => { Alert.alert(err.message); setLoading(false); } );
};
I don't understand what the actual problem is here.
It turned out that problem was okHttp on android. Looks like okHttp appends an empty string " " without a known reason.
Here is how I solved that issue with the workaround:
}).then(response => response.text())
.then((res) => JSON.parse(res.trim())).then(response => {
Related
I make several requests from a React Native app to an API. Every request works fine both on iOS and Android except the DELETE method that does not work on Android. The call is correctly made, it goes through the API and the objects are deleted. But instead of getting the response, the call falls under the catch statement with [TypeError: Network request failed]. This does not happen in iOS.
Some people with the same problem were missing 'Content-Type': 'application/json' on the request headers which is not my case.
This is happening both locally, in testing and production stages (using an ip instead of localhost will do nothing).
The request is also successfully performed in Postman.
What can it be?
React Native 0.63.5
export const deleteApi = async (api: string, body?: any) => {
const userResponse = await getUserCredentials();
const authState = await getAuthState();
let response = await fetch(api, {
method: 'DELETE',
headers: await getHeaders(userResponse, authState),
body: JSON.stringify(body)
});
if (response.status === UNAUTHENTICATED_CODE)
response = await interceptor(response, userResponse, {
api: api,
method: 'DELETE',
body: body
});
return response;
};
leaveClass = async (
uuid: string,
onSuccess: () => void,
onFailure: (error: string) => void,
) => {
this.setLoading(true);
try {
const api = LEAVE_CLASS_API_PREFIX + uuid + LEAVE_CLASS_API_SUFFIX;
const response = await deleteApi(api);
if (response.status === SUCCESS_STATUS_CODE) {
onSuccess();
}
else {
const jsonResponse = await response.json();
if (jsonResponse.detail) onFailure(jsonResponse.detail);
else onFailure(translations.SOMETHING_WENT_WRONG);
}
} catch (error) {
console.log('leaveClass error: ', error);
}
this.setLoading(false);
};
You can use a network plugin for Flipper (https://fbflipper.com/docs/setup/plugins/network/), copy your request from it as a curl, and try to perform it from your terminal or postman. If it has the same error, the problem is not in React Native.
We developed an application with react native.
I will leave the link of the application below, I do not know if this is prohibited.
I pull data with axios, it works on all android devices. But it doesn't work on Xiaomi phones. I could not find the reason for this.
const api = "apiadress/deneme.php?lesid="+getLessonId;
axios.get(api).then((response)=>{
db.transaction((tx) => {
tx.executeSql('UPDATE lessons SET downloaded=? WHERE id=?', ['1',getLessonId]);
});
response.data.map((item) => {
db.transaction((tx) => {
tx.executeSql('INSERT INTO questions (questionname,lessonname,answerbame,aoptionname,boptionname,coptionname,doptionname,eoptionname,lessonid,oldidq) VALUES (?,?,?,?,?,?,?,?,?,?)',
[item.QuestionName,item.LessonName,item.AnswerName,item.AOption,item.BOption,item.COption,item.DOption,item.EOption,item.id,item.Id]);
});
});
console.log("Tüm sorular başarıyla kayıt edildi.");
});
An image of the code
link
I'm not sure what is the problem, but I had the a similar problem with axios (server requests didn't work after deployment)
You should consider leave axios and try using fetch:
POST:
fetch('http://mywebsite.com/endpoint/', {
method: "POST",
headers: {
// Authorization: "Bearer " + Token,
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
// sending data userID username, password, etc
}),
})
.then((response) => response.json())
.then((responseJson) => {
// Response will here
})
.catch((error) => {
alert(error);
});
GET:
fetch('http://mywebsite.com/endpoint/', {
method: "GET",
headers: {
// Authorization: "Bearer " + Token,
// OR USER name PASSworrd
Accept: 'application/json',
'Content-Type': 'application/json'
},
})
.then((response) => response.json())
.then((responseJson) => {
// Response will here
})
.catch((error) => {
alert(error);
});
I'm trying to send a fetch request using post to an api, I'm doing a search using a keyword and it should return a JSON containing users, whenever I try this on Android using expo it doesn't work however it seems to work on iOS using expo. The error I get back is a JSON parse error, I get a status code of 308.
import User from '../../Model/User';
import { BearerToken } from '../../Constants/BearerToken';
export const GETRESULTS = 'GETRESULTS';
export const getResults = (item) => {
return async dispatch => {
const response = await fetch("https://example.com",
{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': BearerToken
},
body: JSON.stringify({
query: item
}),
redirect: 'follow'
}
);
console.log(response.status);
if(!response.ok) {
console.log("fack off");
const errorResData = await response.json();
console.log(errorResData);
let message = 'Something went wrong';
throw new Error(message);
}
const resData = await response.json();
const searchResultsArray = [];
for(const searchResult in resData){
searchResultsArray.push(new User(
resData[searchResult].education,
resData[searchResult].email,
resData[searchResult].full_name,
resData[searchResult].gender,
resData[searchResult].job_title,
resData[searchResult].location,
resData[searchResult].password,
resData[searchResult].phone,
resData[searchResult].preferred_name,
resData[searchResult].profile_image,
resData[searchResult].profile_type,
resData[searchResult].score,
resData[searchResult].short_bio,
resData[searchResult].story
)
);
}
dispatch({type: GETRESULTS,usersArray:searchResultsArray});
};
};
What worked for me was putting 'https://example.com/search/' basically at a slash at the end fixed it for me
I'm trying to send/upload image file to my back-end serve using fetch multipart upload in react-native, but fetch multipart form data upload is not working for android, however I tried different examples.
Image upload multipart form data API is based on php and its working for iOS react-native app.
I am using react-native-photo-upload library for taking image.
storePicture(PicturePath:string) {
console.warn(PicturePath);
if (PicturePath) {
const apiUrl = `${Constants.APIHOST}updateprofileimage.php`;
// Create the form data object
var data = new FormData();
data.append('profileimage', { uri:PicturePath, name: 'profileimage.jpg', type: 'image/jpg/jpeg' });
data.append('accesstoken', this.state.user.sAccessToken);
data.append('react-native', 1);
// Create the config object for the POST // You typically have an OAuth2 token that you use for authentication
const config = { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'multipart/form-data;' }, body: data };
fetch(apiUrl, config)
.then(responseData => { // Log the response form the server
// Here we get what we sent to Postman back
console.warn(`response:${responseData}`);
})
.catch(err => {
console.warn(err);
});
}}
Here is the example how I am calling storePicture() function.
<PhotoUpload onResizedImageUri={
avatar => {
if (avatar) {
this.storePicture(avatar.path);
}
}}
>
<Image source={{uri: this.state.user.sProfileImageUrl}} style={{resizeMode:"cover", marginTop:8.0, backgroundColor:'transparent', height:120.0, width:120, borderRadius:60.0, borderWidth:0.0, borderColor:'transparent'}}/>
</PhotoUpload>
uploadProfileImage = async (image:var) => {
this.setState({
loading: true
});
var RNFS = require('react-native-fs');
const path = Style.IS_IOS ? image.uri : image.path;
var fileName = path.split('/').pop();
var fileType = fileName.split('.').pop();
var filePath = Style.IS_IOS ? path : 'file://' + path;
const apiURL = `${Constants.APIHOST}updateprofileimage.php`;
const formData = new FormData();
formData.append('accesstoken', this.state.user.sAccessToken);
formData.append('reactnative', 1);
formData.append('profileimage', {
uri:filePath,
name: fileName,
type: `image/${fileType}`,
});
try {
const response = await fetch(apiURL, {
body: formData,
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
'Accept': 'application/json',
},
})
const json = await response.json()
this.handleUploadImageResponse(json);
} catch (err) {
this.setState({
loading: false
},console.log('catch Error: '+ err));
}
}
I am answering my own question as I haven't found any valid answer for the sake of other users, who are facing same issue.
Please let me know if I can improve my answer/post or in case any help is needed from me.
Image Upload to an API by Multipart FormData
uploadPicture = () => {
console.log(
"Image Upload urI = " + JSON.stringify(this.state.imageSourceUri.uri)
);
this.setState({ loading: true });
const form = new FormData();
form.append("fileToUpload", {
uri: this.state.imageSourceUri.uri,
type: "image/jpg",
name: "12334"
});
fetch("http://119.82.97.221/HPBSProjectApi2/api/HPBS/PostFormData", {
method: "post",
body: form
})
.then(response => response.json())
.then(response => {
console.log("response = " + response);
this.setState({
loading: false
});
});
};
the problem is the type field in the FormData, use mime to resolve it. Images must be image/jpeg.
const formData = new FormData();
formData.append("image",{..., name, uri, type: mime.getType(uri)}));
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Trying to call an API to my backend with Fetch, but I can't access the response body. There's a loot of different notation and syntax about this on the internet and I can't figure out how to do it properly.
I've tried response.json() and responseJson, and stringyfying both. I don't get what I want which is the actual body of the response. It's meant to have a key/token that I then save.
responseJson returns this: responseJson:
{"_40":0,"_65":0,"_55":null,"_72":null}
This is my function:
export function LogIn(em, pass) {
return (dispatch) => {
console.log('LogIn called');
dispatch(logInIsLoading(true));
//from phone
*fetch('http://192.168.1.18:8080/rest-auth/login/', {
method: 'POST',
headers: {
// 'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
'email': em,
'password': pass,
})
}).then((response) => {
console.log("response " + JSON.stringify(response));
if (!response.ok) {
console.log("ERROR: " + response.statusText);
throw Error(response.statusText);
}
dispatch(logInIsLoading(false));
return response;
})
.then((response) => {
responseJson = response.json();
console.log("responseJson: " + JSON.stringify(response.json()));
return responseJson
})
.then((responseJson) => {
AsyncStorage.multiSet([['key', responseJson.key], ['loggedIn', true]], () => {
console.log(responseJson.key);
dispatch(isLoggedIn(true));
dispatch(getKey(responseJson.key));
});
})*
.catch(() => dispatch(logInHasErrored(true)));
};
}
This is the response, but I can't get to the key in the body:
response {"type":"default","status":200,"ok":true,"headers":{"map":
{"allow":["POST, OPTIONS"],"set-cookie":
["csrftoken=DOMxD5IhNz5Vwm9a3niAR1tRyqBfNzUqnQMAEgk7AGwtwCgnRnZo9x0AMTM2IfK
q; expires=Fri, 22-Feb-2019 17:31:58 GMT; Max-Age=31449600; Path=/,
sessionid=er3fujv8ji96t41n1n8dlzb3zz1itwuj; expires=Fri, 09-Mar-2018
17:31:58 GMT; httponly; Max-Age=1209600; Path=/"],"content-type":
["application/json"],"content-length":["50"],"x-frame-options":
["SAMEORIGIN"],"vary":["Accept, Cookie"],"server":["WSGIServer/0.1
Python/2.7.14"],"date":["Fri, 23 Feb 2018 17:31:58
GMT"]}},"url":"http://192.168.1.18:8080/rest-auth/login/","_bodyInit":"
{\"key\":\"a9951fd6abff4fed35d9a8d1c275bf1212887513\"}","_bodyText":"
{\"key\":\"a9951fd6abff4fed35d9a8d1c275bf1212887513\"}"}
response.json() return Promise
AsyncStorage.multiSet - return Promise. Second parameter of multiSet is Function that will be called with an array of any key-specific errors found
export function LogIn(em, pass) {
return (dispatch) => {
console.log('LogIn called');
dispatch(logInIsLoading(true));
fetch('http://192.168.1.18:8080/rest-auth/login/', {
method: 'POST',
headers: {
// 'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
'email': em,
'password': pass,
})
}).then((response) => {
if (!response.ok) {
console.log("ERROR: " + response.statusText);
throw Error(response.statusText);
}
dispatch(logInIsLoading(false));
return response;
})
.then((response) => {
return response.json()
})
.then((responseJson) => {
console.log('responseJson', responseJson);
return AsyncStorage.multiSet([['key', responseJson.key],['loggedIn', true]], () => {
dispatch(logInHasErrored(true));
})
.then(() => {
dispatch(isLoggedIn(true));
dispatch(getKey(responseJson.key));
})
})
.catch(() => dispatch(logInHasErrored(true)));
};
}
This is pretty straight forward with axios.
First install axios by doing npm install --save axios
Then inside your Component do this:
handleInput = async() => {
const res = await axios.post('http://192.168.1.18:8080/rest-auth/login/', {
email: this.state.email,
password: this.state.password
});
const data = await res.json();
console.log(data);
}
Make sure you've stored email and password in this.state.email and this.state.password respectively and call handleInput when user presses the Submit button.
Don't forget to import axios import axios from 'axios'