As per https://github.com/facebook/react-native/pull/1357#issuecomment-171378913 @philikon implemented uploading files (images) via the NetworkingModule.java.
The following works on iOS (image and description are sent to server and received correctly) on iOS. On Android, the request is made but both image and description are missing from the request.
let formData = new FormData();
formData.append('image', {uri: image.uri, type: 'image/jpg', name: 'image.jpg'});
formData.append('description', String(data.description));
let options = {};
options.headers['Content-Type'] = 'multipart/form-data; boundary=6ff46e0b6b5148d984f148b6542e5a5d';
options.body = formData;
return fetch(uri, options).then((response) => {
....
});
Where image.uri
is either an android or ios file:
file:///storage/emulated/0/Pictures/eb645893-4c00-44a3-a9b4-a2116e955f7c.jpg
/Users/ashleydw/Library/Developer/CoreSimulator/Devices/23EE88D0-6E91-43AD-A3B6-06F87698C5A8/data/Containers/Data/Application/A73E68D3-7424-4301-9934-AD0F8251C1EB/tmp/7803DA8A-0E40-4FCB-A593-884805878172.jpg
I've tried both with and without it file://
. Without it, the NetworkingModule.java reaches "Could not retrieve file for uri /storage/emulated/0/Pictures/8505b7c8-389e-4a0a-8d0a-7669891031f9.jpg" on line https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java#L166.
With it, the requests send but the data is missing.
Hey ashleydw, thanks for reporting this issue!
React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.
react-native
or for more real time interactions, ask on Discord in the #react-native channel.@ashleydw first off, you should not be setting your own content type header. The point of using FormData
is that FormData
takes care of that, in particular generating a random boundary etc.
As for your problem, have you tried using regular XMLHttpRequest
? Just to rule out fetch
as a source of the bug.
Also, just to rule out weirdness with your server, have you tried using another server to verify that your data is indeed not being sent, e.g. https://www.posttestserver.com? The UIExplorer app does that. The iOS version actually uploads an image: https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/XHRExample.ios.js#L217. The Android version doesn't (yet), but it could easily be modified to do so (perhaps you can submit a PR?).
Also, #4894 might be related...
Me too hit the problem until I have to revamp my server API to support base64 upload.
It was annoying me because RN Android supports XMLHttpRequest multiform file upload in terms of documentation (Assuming all multiform support standards should include uploading files), but not in code actually. I wish to push it to ProductPains now.
Guys, if FormData doesn't work for you. You can try this https://github.com/PhilippKrone/react-native-fileupload This works for iOS and android too. I forked it and fixed the Content-Disposition and Content-Type for android
https://github.com/rpopovici/react-native-fileupload
It is unclear yet how exactly RN's behaviour is broken. FormData
works fine with binary files such as images with the Facebook Graph API, so it only seems to be broken in some cases. I'd like to track down those cases, but I need your help. @ashleydw, @VansonLeung et.al., could you please elaborate what the problem is specifically? For instance, a test case / piece of demo code run against a test server (e.g. https://www.posttestserver.com) would help greatly. If you post the code and the link of your upload result here, we can see what React Native is actually uploading.
@VansonLeung: can you elaborate on the base64 issue? Is React Native using Content-Transfer-Encoding: Base64
for the binary blob? Or what is the problem?
@rpopovici: I think it's great that react-native-fileupload exists, but I think fundamental webby behaviour such as form data APIs should work flawlessly in React Native. I've reached out to @PhilippKrone in the past hoping we could just add his work into React Native proper. If you have any insight and/or fixes to contribute to R/N, that'd be greatly appreciated!
Removing the Content-Type
header resolved this.
Can you confirm that this solution (using fetch + FormData with no Content-Type header) works in android. I just get a _[TypeError: Network request failed]_ error. Same code works fine in IOS.
let xhr = new XMLHttpRequest();
xhr.open('POST', this.baseUrl + '/mobileapi/user/picture');
let formdata = new FormData();
// image from CameraRoll.getPhotos(
formdata.append('image', {...image, name: 'image.jpg', type: 'image/jpeg'});
xhr.send(formdata);
This works on Android
Finally Android gets it working!
Thank, It work for me
xhr.setRequestHeader('content-type', 'multipart/form-data');
You should not have to specify this.
formdata.append('image', {...image, name: 'image.jpg', type: 'multipart/form-data'});
That content-type is simply wrong. You want image/jpeg
or something like that.
@philikon You are totally right!
Using RN 27 I had to both remove my boundary: section from the multipart header and add the file:// prefix if Platform.OS === 'android'
(Still using FormData()) Thanks for your pointers.
It works on Android, but not on iOS for me..
I'm using RN 0.40+
In my case, multiples photos, I solved problem with below code.
let data = new FormData()
_.each(params.photos, (photo) => {
data.append('photos[]', {uri: photo.uri, type: photo.type, name: photo.fileName});
})
data.append('title', params.title)
data.append('description', params.description)
data.append('price', params.price)
data.append('city', params.city)
data.append('state', params.state)
data.append('status', params.status)
data.append('category_id', params.category_id)
data.append('user_id', params.user_id)
const response = await fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
'Authorization': `Bearer ${params.token}`
},
body: data
})
I think there is a problem if you use 'image/jpg' instead of the correct one: 'image/jpeg'
Not sure if this can cause a problem or just having the incorrect type is the reason.
Check: Media Types
@hugomosh you saved my day. using image/jpeg fixed it.
RN 0.47
For android to work I needed to remove 'Content-Type': 'multipart/form-data',
from the headers
object.
Some things to keep in mind:
When adding photos in android or ios at a FormData object i would use index when using data.append in the data object because my nodejs server (using formidable) doesn't count the post requests array of photos[]
_.each(params.photos, (photo, index) => {
data.append('photos['+index+']', {uri: photo.uri, type: photo.type, name: photo.fileName});
})
uri
part on android is differentIt means that android requires you to include "file:///data/dir/photo.jpg" on the uri part inside a FormData object
For example when inserting a photo i would use:
const generated_photo_uri = '/data/data/com.google.app/cache/1520712375005.JPEG';
data.append('photo', {uri: (Platform.OS==='android?'file://':'')+generated_photo_uri, type: 'image/jpeg', name: 'my-photo.jpg'});
@a3diti you have a typo on the 2nd item, it should be:
(Platform.OS==='android' ? 'file://' : '') + generated_photo_uri
Most helpful comment
This works on Android