Axios in React Native doesn't provide Form-Data headers - react-native

I'm trying to upload a file via Axios (Version ^0.26.0) in React Native (Version 0.66.4) with the following code:
const formData = new FormData();
formData.append('image', {
uri: 'aFilePathProvidedByTheImagePicker',
name: 'file.jpg',
type: 'image/jpg'
});
const response = await this.axiosInstance.put('aCustomUrl', formData, {
headers: {
'Content-Type': 'multipart/form-data;',
},
});
But it always fails with the status code 400. I tried the requested endpoint with Postman and it works fine.
After some debugging and comparing the requests from axios and postman I found out that the Content-Length header is missing. Also a boundary in Content-Type isn't provided. See the screenshots below:
Postman:
Reicht Native Debugging:
I also read about the formData.getLengthSync() but in react native it leads to the error formData.getLengthSync is not a function
Does anyone has a solution for this issue?
According to this post downgrading axios to version 0.24.0 works as a workaround.
(for debugging purpose I used the build in fetch-api which works as expected. but I'd prefer using axios for using a shared instance with request and response interceptors)

This issues is solved in Axios Version 0.27.2 (https://github.com/axios/axios/issues/4460#issuecomment-1115163147)

Your code should work but you could try to add content-type to headers
"Content-Type": "multipart/form-data; boundary=" + formData .getBoundary(),

Related

Why in React Native post request can't be sent?

I am using axios in react native project but at the time of post request through axios it gives an error
export const login = (email, password) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
};
const body = JSON.stringify({ email, password });
console.log(body)
const res = await axios.post(`http://localhost:8000/auth/jwt/create/`, body, config);
console.log('kk');
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
dispatch(load_user());
};
On postman this axios request is executing successfully and on the same backend address my react JS project is working correctly and this axios request also get successful.
On react native project it gives following error.
I've also tried try and catch blocks but after execting axios.post line it goes to catch block .
I've tried the same request on Postman and it's successfully sent the post request and get the tokens
Solution 1
Check this. Maybe you should set android:usesCleartextTraffic="true" in your AndroidManifest.xml file.
Solution 2
I could suggest the next command which I personally always use when developing RN apps on Android using local emulators. adb reverse tcp:8081 tcp:8081.
Solution 3
Use concrete local ip-address instead of localhost alias. Check this.

form post with file attach throws network error / React Native + react native Image picker

I am using react-native-image-picker to fetch image details and try to upload in https backend server. the request is not successful and it throws network error. It did not esablish the connection with the backend server. The problem is with formdata that I am sending. Can you please suggest header and other information, if I missed out.
export const postImage = async state => {
let formData = new FormData();
formData.append('image', {
uri : state.photo.uri,
type: state.photo.type,
name : state.photo.fileName
});
const config = {
headers: {
'Content-Type': 'multipart/form-data',
Accept: "application/x-www-form-urlencoded",
'Accept': 'application/json'
},
};
try {
return $http.post('/image/save', formData, config)
.then(response => response)
.catch(error => error)
} catch(error) {
console.log(error)
}
}
Environment:
- Axios Version ^0.19.2
- Additional Library Versions [React 16.11.0, React Native 0.62.1]
There's an issue with flipper, upgrading it to 0.39.0 and above works
This issue is being tracked here: https://github.com/facebook/react-native/issues/28551
Fix: https://github.com/facebook/flipper/issues/993#issuecomment-619823916
This should be fixed in version 0.39.0. To upgrade, edit android > gradle.properties
# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.39.0 // edit this manually
This issue took me more than 5 hours to resolve. I was about to give up when I was finally able to resolve the issue.
The issue that I was facing which is close to what you are mentioning is that I was getting NetworkError when using expo-image-picker and trying to upload the file using axios. It was working perfectly in iOS but not working in android.
This is how I solved the issue.
There are two independent issues at action here. Let's say we get imageUri from image-picker, then we would use these following lines of code to upload from the frontend.
const formData = new FormData();
formData.append('image', {
uri : imageUri,
type: "image",
name: imageUri.split("/").pop()
});
The first issue is with the imageUri itself. If let's say photo path is /user/.../path/to/file.jpg. Then file picker in android would give imageUri value as file:/user/.../path/to/file.jpg whereas file picker in iOS would give imageUri value as file:///user/.../path/to/file.jpg.
The solution for the first issue is to use file:// instead of file: in the formData in android.
The second issue is that we are not using proper mime-type. It is working fine on iOS but not on Android. What makes this worse is that the file-picker package gives the type of the file as "image" and it does not give proper mime-type.
The solution is to use proper mime-type in the formData in the field type. Ex: mime-type for .jpg file would be image/jpeg and for .png file would be image/png. We do not have to do this manually. Instead, you can use a very famous npm package called mime.
The final working solution is:
import mime from "mime";
const newImageUri = "file:///" + imageUri.split("file:/").join("");
const formData = new FormData();
formData.append('image', {
uri : newImageUri,
type: mime.getType(newImageUri),
name: newImageUri.split("/").pop()
});
This is an issue with flipper.Upgrade the flipper version in gradle.properties to 0.43.0+ and it will be fixed
Make sure the mime type matches the file you are uploading.
For me, it was the issue.
change this line: form_data.append('image', data);
To form_data.append('image', JSON.stringify(data));
where data is from the image picker.
from https://github.com/react-native-image-picker/react-native-image-picker/issues/798
You need to add this uesCleartextTraffic="true" to the AndroidManifest.xml file found inside the dir android/app/src/main/AndroidManifest.xml
<application ... android:usesCleartextTraffic="true"> Then, Because of issue with Flipper Network.
I commented initializeFlipper(this, getReactNativeHost().getReactInstanceManager())
in this file /android/app/src/main/java/com/{your_project}/MainApplication.java
Also, commenting out line number 43 in this file android/app/src/debug/java/com/**/ReactNativeFlipper.java
line43: builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
None of the issues in the other answers were causing my problem, but after digging more into Axios error response, I found out that Nginx was responding with error 413 Request Entity Too Large.
Adding client_max_body_size 50M to the http section of nginx.conf file solved the issue.

Is it possible to use $http of AngularJS as stand alone application?

$http is a nice aspect of AngularJS. But can we use it without AngularJS?
For example:
<script src="LIBRARY/http.js"></js>
var req = {
method: 'POST',
url: 'http://example.com',
headers: {
'Content-Type': undefined
},
data: { test: 'test' }
}
$http(req).then(function(){...}, function(){...});
The intention is to use $http without AngularJS. (Usage example copied from the documentation.)
I haven't come across standalone http package provided by angular but axios is another library that is similar to angularJs http module. Both axios and http are promise based http clients. I'd say using axios would be better than bringing entire angularJs library.
https://github.com/axios/axios
https://www.npmjs.com/package/axios

fetch sends [object Object] instead of File object

I'm using Expo and its ImagePicker to grab the image from gallery. It returns both uri and base64.
Now I want to upload the image in a multipart/form-data request.
The problem is that the server only accepts File while below code sends [object Object] instead.
Image of the request
const formData = new FormData();
const data = {
jwt,
};
formData.append('message', JSON.stringify(data));
formData.append('avatar', {
uri: avatar,
type: 'image/png',
name: 'avatar.png'
});
fetch(url, {
method: 'POST',
body: formData,
headers: {
Accept: 'application/json',
},
})
Since I'm using Expo I'm limitted to libraries that it supports. Also adding Content-Type header doesn't work at all and server can't even recognize the message.
If you see that file being sent as [object object] in your request params, that might occur due to two reasons:
The file that you are sending is not a file (or not a file object).
A FormData should only receive a File or a Blob object in order to be sent on a request.
Note that you have the right keys on your object and that it is indeed a File or a Blob.
As mentioned, it might be the Content-Type header which should not be set
For React, if you want to upload image and avoid [object object] error, there is a need to setFile for input type handleChange
const file = event.target.files[0]
setFile({
picturePreview: URL.createObjectURL(event.target.files[0]),
pictureAsFile: event.target.files[0]
})
And then calling in formData like:
formData.append('file_attachment', file.pictureAsFile)
Full working example here: https://youtu.be/yTGXNvHQ4BQ

react native fetch not sending body content

I am new to fetch in react native and followed this tutorial.
I am trying to send a json body to an private api server, I checked the server log and found out that the body content is empty.
Here is the code in react native
authenticateLogIn(){
fetch('<URL>', {
method: 'POST',
header: {'Content-Type': 'application/json', 'Accept': 'application/json'},
body: JSON.stringify({'username': '<username>', 'password':'<password>'})
})
.then((incoming) => incoming.json())
.then((response) => {
console.log(response.header);
Alert.alert(JSON.stringify(response.body));
})
.done();
Maybe because it shoueld be headers? (with the s)
It might be because your JSON body isn't being parsed correctly. bodyParser https://github.com/expressjs/body-parser is part of the middleware that parses request bodies and needs to be configured.
req.body kept coming back empty for me until I added app.use(bodyParser.json() into server.js file. Make sure you import body-parser.