I need to upload large video files in the background.
What is the best way to achieve this?
I tried using this library (react-native-background-upload). But the problem is, I can't send any other data along with the video file. The API expects the following data:
{
projectId: number,
title: string,
video: file,
};
This is the piece of code to send the files with multipart using the library:
const options = {
url: url,
path: pathToVideoFile,
method: 'POST',
field: 'video',
type: 'multipart',
};
Are there any alternatives that I can use? Can react-native-background-fetch be used for this use case?
in react-native-background-upload
you can use parameters in options to send additional data
Additional form fields to include in the HTTP request. Only used when type: 'multipart
const options = {
url: url,
path: pathToVideoFile,
method: 'POST',
field: 'video',
type: 'multipart',
parameters : {
key1: "value1",
key2: "value2",
}
};
you can see all options params here here
you can install react-native-compressor package which is made by me
Installation
yarn add react-native-compressor
Usage
import {Video} from 'react-native-compressor';
const headers={
'Content-Type': '',
}
const uploadResult = await Video.backgroundUpload(
"http://w.hbu50.com:8080/hello.mp4",
fileUri,
{httpMethod: 'PUT', headers},
(written, total) => {
onProgress({
status: 'uploading',
progress: written / total,
uploading: true,
});
},
);
Related
If I'm not mistaken, to be able to upload a file to S3 you have to use a similar code:
await Storage.put(
e.target.files[0].name,
e.target.files[0],
{ contentType: e.target.files[0].type }
);
Is that way best and secure way? Are you sure?
Indeed, imagine I have the following scenario:
Scenario 1: Files must be uploaded in specific folders
Example:
const user_id = '30e29fc1-4718-4f35-9908-729d63477114';
await Storage.put(
user_id + '/' + e.target.files[0].name,
e.target.files[0],
{ contentType: e.target.files[0].type }
);
Anyone can override this condition by changing the path.
Example:
await Storage.put(
'other_path/' + e.target.files[0].name,
e.target.files[0],
{ contentType: e.target.files[0].type }
);
--> How to force users' files to be uploaded to their own folder?
Scenario 2: Upload the file then save the path in the DynamoDB database
Example:
const { key } = await Storage.put(
e.target.files[0].name,
e.target.files[0],
{ contentType: e.target.files[0].type }
);
const inputPost = {
id: uuid(),
title: 'My title',
content: 'My content',
filePath: key
};
await API.graphql(graphqlOperation(createPost, {input: inputPost}));
Anyone can override this condition by setting the filePath parameter.
Example:
const inputPost = {
id: uuid(),
title: 'My title',
content: 'My content',
filePath: 'perfume.jpg' // the file path of a file that does not belong to me
};
await API.graphql(graphqlOperation(createPost, {input: inputPost}));
--> How to prevent this kind of thing?
I show many many video tutorial with that practices. Are there ok?
Best Regard
Thank you
MEMO:
With Firebase, I have the same problem but I can set some Rules:
https://firebase.google.com/docs/storage/security
https://firebase.google.com/docs/reference/security/storage
I'm using rn-fetch-blob library to upload some pictures to the server. But I'm getting different types of errors, such as no Boundary on Content-Type or errors with the FormData structure itself such as " of type NSMutableDictionary cannot be converted to NSString", I'm getting quite frustrated.
I got an image array like this:
var images = [
{name 'pic1', data: RNFetchBlob.wrap(imagePathHere), type: 'image/jpeg'},
{name 'pic2', data: RNFetchBlob.wrap(imagePathHere), type: 'image/jpeg'},
{name 'pic3', data: RNFetchBlob.wrap(imagePathHere), type: 'image/jpeg'},
];
Then I create the FormData as follows:
const formData = new FormData();
formData.append('id', userId) // <-- numeric type
formData.append('pictures', images);
I'm doing the post request from RNFetchBlob with 'Content-Type': 'multipart/form-data' and I pass the formData directly to it.
Any ideas on what's wrong ? I read somewhere that FormData only allows strings or blobs, should I create a Blob from my array? How can I do that?
Thanks in advance.
After a lot of struggle, I found a solution in some other github about the structure I had to pass for parameters.
This would be the correct one for my specific case.
var reqData = [
{ name: 'id', data: response.data.id }
];
this.state.images.forEach((image) => {
reqData.push({
data: image.imageFile,
filename: image.fileName.split('.')[0] + '.jpg',
name: 'pictures',
type: image.type
})
});
But basically this would be an example of it:
var params = [
{
name: 'id',
data: 43
},
{
name: 'image',
data: RNFetchBlob.wrap(imagePath),
filename: 'image1.jpg',
type: 'image/jpeg'
},
{
name: 'image',
data: RNFetchBlob.wrap(imagePath),
filename: 'image2.jpg',
type: 'image/jpeg'
},
];
I have simple image upload via action and mutation. The main thing is that I firstly want to store preloader and then, when the image is uploaded to the server show the image and remove preloader.
export default new Vuex.Store({
state: {
images: [],
},
mutations: {
addImage(state, image) {
state.images.push(image);
}
},
actions: {
saveImage({commit}, image) {
commit('addImage', {url: 'http://via.placeholder.com/100x100?text=loading...'});
let form_data = new FormData();
form_data.append('file', image);
return new Promise((resolve, reject) => {
jQuery.ajax({
url : '/api/v1/products/files/save',
data : form_data,
type : 'POST',
cache: false,
contentType: false,
processData: false,
success: response => {
// commit('addImage', response.file);
// here I somehow need to replace/readd the response.file
resolve(response.file)
}
}).fail(() => reject())
})
}
},
strict: debug
})
I basically could use array.find method to look for url:http://via.placeholder.com/100x100?text=loading... remove it and then add new one but not sure if it's is the right method...
You give vuex action too much to do. Let it do one single task - upload the file. The placeholder/preloader should be handled by the component even without a vuex state. All the component needs to know is whether the image is uploading or not in order to show the loading indicator. Since your action returns a Promise your component will know when it's ready.
I am trying to use react-native-fetch-polyfill becouse of timeout feature for fetch requests but can't implement onProgress event:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
.then(function(data) {
console.log(data);
})
.catch(function(error) {
console.log('Fetch Error :-S', error);
});
I don't know where to add:
onUploadProgress: function (progressEvent)
That library does not support progress handler. If you need this feature and want to use that library, the simplest thing for you to do would be to fork the library and add the feature yourself:
1) Fork the repository on GitHub.
2) Edit js file in your repository. For example, add callback you need as a third argument to the function:
export default function fetchPolyfill (input, init) {
// becomes
export default function fetchPolyfill (input, init, onUploadProgress) {
// add this somewhere inside
if (onUploadProgress)
xhr.upload.onprogress = onUploadProgress
3) Edit your package json to include
"react-native-fetch-polyfill": "git://github.com/youraccount/react-native-fetch-polyfill"
and run npm install.
1a) Of course you may actually just copy the script and edit it locally on your computer without dealing with GitHub, if you are fine with it not being in node modules. Or download the whole folder and use it as a package.
You can use axios
that already have thus function (onUploadProgress)
Under the hood, fetch uses the React-Native XMLHttpRequest object; this is also true for react-native-fetch-polyfill. This is not the regular xhr object which is used in browsers since the actual requests are sent from the native side.
As far as I know, both RN fetch and react-native-fetch-polyfill do not support upload progress, but you can use XMLHttpRequest directly to do that:
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = (progressEvent) => {
//handle progress here, you can use progressEvent.loaded, progressEvent.total to calculate the progress
};
const body = JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
});
xhr.setRequestHeader("Content-type", "application/json; charset=UTF-8");
xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts');
xhr.send(body);
you can also add the timeout handling yourself:
xhr.timeout = 30 * 1000;
xhr.ontimeout = () => {
//handle timeout here
}
I have problem with uploading files from my ember.js frontend to grails backend. I can't use any of ember plugins like ember-uploader because of supporting IE8. Any advices how to solve this problem ?
BlueImp's jQuery File Upload claims it supports IE 6+. Read more about it:
https://github.com/blueimp/jQuery-File-Upload
I use it via an Ember component like this:
{{file-upload uploadUrl=uploadUrl filename="files"
buttonText="Upload files"
hiddenName="fileId" hiddenValue=fileId
uploaded="filesUploaded"}}
and initialize the plugin in the component's didInsertElement:
didInsertElement: function() {
var self = this;
this.$('#'+this.get('inputId')).fileupload({
dataType: 'json',
url: this.get('uploadUrl'),
formData: function() {
return [{name: self.get('hiddenName'), value: self.get('hiddenValue')}];
},
done: function(e, data) {
self.sendAction('uploaded', data.result);
self.markCompleted(data.result.filenames);
},
fail: function (e, data) {
self.sendAction('failed', data.result);
},
add: function(e, data) {
data.process().done(function () {
data.submit();
});
},
});
Thanks for response kielni, but I used different approach than yours.
I used solution from this blog post: Cross-browser AJAX uploads with Ember.js and mOxie
And code in component that worked for me:
var fileInput = new mOxie.FileInput({
browse_button: this.$('.file-pick-button').get(0),
multiple: false
});
fileInput.onchange = function (e) {
var file = fileInput.files[0];
var reader = new mOxie.FileReader();
reader.onloadend = function () {
ajax({
type: "POST",
timeout: 5000,
url: config.serverURL + '/files/',
data: {
transportID: id,
filename: file.name,
file: reader.result
}
});
};
reader.readAsBinaryString(file);
};
fileInput.init();