Reputation: 510
I have an Electron app which is able to upload very big files to the server via HTTP in renderer process without user input. I decided to use axios
as my HTTP client and it was able to retrieve upload progress but with this I met few problems.
Browser's supported js and Node.js aren't "friendly" with each other in some moments. I used fs.createReadStream
function to get the file but axios
does not understand what ReadStream
object is and I can't pipe (there are several topics on their GitHub issue tab but nothing was done with that till now) this stream to FormData
(which I should place my file in).
I ended up using fs.readFileSync
and then form-data
module with its getBuffer()
method but now my file is loaded entirely in the memory before upload and with how big my files are it kills Electron process.
Googling I found out about request
library which in-fact is able to pipe a stream to request but it's deprecated, not supported anymore and apparently I can't get upload progress from it.
I'm running out of options. How do you upload files with Electron without user input (so without file input) not loading them in the memory upfront?
P.S. on form-data
github page there is a piece of code explaining how to upload a file stream with axios
but it doesn't work, nothing is sent and downgrading the library as one issue topic suggested didn't help either...
const form = new FormData();
const stream = fs.createReadStream(PATH_TO_FILE);
form.append('image', stream);
// In Node.js environment you need to set boundary in the header field 'Content-Type' by calling method `getHeaders`
const formHeaders = form.getHeaders();
axios.post('http://example.com', form, {
headers: {
...formHeaders,
},
})
.then(response => response)
.catch(error => error)
Upvotes: 4
Views: 2744
Reputation: 510
I was able to solve this and I hope it will help anyone facing the same problem.
Since request
is deprecated I looked up for alternatives and found got.js for NodeJS HTTP requests. It has support of Stream
, fs.ReadStream
etc.
You will need form-data as well, it allows to put streams inside FormData
and assign it to a key.
The following code solved my question:
import fs from 'fs'
import got from 'got'
import FormData from 'form-data'
const stream = fs.createReadStream('some_path')
// NOT native form data
const formData = new FormData()
formData.append('file', stream, 'filename');
try {
const res = await got.post('https://my_link.com/upload', {
body: formData,
headers: {
...formData.getHeaders() // sets the boundary and Content-Type header
}
}).on('uploadProgress', progress => {
// here we get our upload progress, progress.percent is a float number from 0 to 1
console.log(Math.round(progress.percent * 100))
});
if (res.statusCode === 200) {
// upload success
} else {
// error handler
}
} catch (e) {
console.log(e);
}
Works perfectly in Electron renderer process!
Upvotes: 5