简体   繁体   中英

Electron upload with progress

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?

PS 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)

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM