Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fetch does not support posting files as multipart/form-data #9684

Closed
ProPuke opened this issue Jun 6, 2017 · 8 comments
Closed

fetch does not support posting files as multipart/form-data #9684

ProPuke opened this issue Jun 6, 2017 · 8 comments

Comments

@ProPuke
Copy link

ProPuke commented Jun 6, 2017

  • Electron version: 1.7.2
  • Operating system: Windows 7 Home Premium

Expected behavior

Amending a file to a FormData instance and then POSTing it with fetch from the renderer should include the file contents as multipart/form-data

let data = new FormData();
data.append('file', fs.createReadStream(filename), path.basename(filename));

fetch(url, {
    method: 'POST',
    body: data
});

Actual behavior

The file parameter is passed with no value and the filename parameter is ignored.
Using a Blob instead of a fs.ReadStream, the filename parameter is honoured and data sent, but unfortunately incorrect data is sent.

How to reproduce

let data = new FormData();
data.append('file', fs.createReadStream(filename), path.basename(filename));

fetch(url, {
    method: 'POST',
    body: data
});

Check the network tab in Developer Tools and verify there is no filename or data on the request data

@ProPuke
Copy link
Author

ProPuke commented Jun 7, 2017

Amend to the above - Using Blobs does send data (and the filename parameter is honoured). But it's incorrectly represented (sent as a stream of ascii byte values with no separators, rather than a binary stream)

@tguillemot
Copy link

@ProPuke I encounter the same problem.
Do you find a way to solve it ?

@ProPuke
Copy link
Author

ProPuke commented Oct 23, 2017

@tguillemot Yeah, I ended up doing it using node and request, instead:

const fs = require('fs');
const request = require('request').defaults({jar: true});
const {remote} = require('electron');
const {dialog} = remote;
request.post({
    url: url,
    formData: {
        file: fs.createReadStream(filename)
    }
}, (err, res, body) => {
    if(err){
        dialog.showErrorBox('Error uploading file', `Something went wrong (${res.statusCode})`);
        return;
    }

    // hande body...
})

I prompt the user for the file with

dialog.showOpenDialog(remote.getCurrentWindow(), options, callback);

then in callback pass the first filename to that request post.

(as you can see I did it in the renderer, making use of remote, but might be neater to do it in main via an ipc event)

The downside to using node instead of the renderer, is that this transfer won't show in the dev tools under network; So you're working a bit more blind.

@tguillemot
Copy link

Thanks for your solution @ProPuke.

For the record, I have used an input type file instead of the fs.createReadSteam to post my file (which is easier in my case). I had another problem because I used the external lib form-data instead of the one of electron widow.FormData.
This comment from the form-data library was really helpful to solve the problem : form-data/form-data#271 (comment).

@MarshallOfSound
Copy link
Member

We are no longer implementing bugfixes for versions of Electron <= 1.7.x, so I'm going to close this issue but if it is still persisting in more recent versions of Electron we can certainly reopen it!

@ericpyle
Copy link

ericpyle commented May 8, 2019

@MarshallOfSound I hate to want to re-open this, but I'm still hoping that multipart/form-data with file streaming could be supported by electron's fetch. As far as I can tell, it's still not supported as of Electron 4.1.3. Third party request solutions above are not logged in Chrome's devtools Network tab making app debugging painful.

I had been using the npm request package workaround above (albeit via the npm request-promise-native package v1.0.7) with Electron 1.7.11. Unfortunately, that stopped working when I merged to the latest electron-react-boilerplate/next (Electron 4.1.3).

When I try building the multipart/form using Electron fetch:

  const data = new FormData();
  const filename = path.basename(filePath);
  data.append('content', fs.createReadStream(filePath), filename);
  return fetch(fullUri, {
    headers: { ...authHeader() },
    method: 'POST',
    body: data
  });

I get the Response No content provided as file from the Request & Form Data in Network tab:

POST /bundle/fbc173e8-81ca-4c2c-a32f-de6ccd337b99/resource/MAT_001.mp3 HTTP/1.1
Host: 127.0.0.1:44151
Connection: keep-alive
Content-Length: 138
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0aGVkaWdpdGFsYmlibGVsaWJyYXJ5Lm9yZyIsImV4cCI6NDcxMDk0MzIzMCwiaWF0IjoxNTU3MzQzMjMwLCJzdWIiOiJFcmljIFB5bGUiLCJrZXkiOiJlcmljX3B5bGVAc2lsLm9yZyIsImVtYWlsIjoiZXJpY19weWxlQHNpbC5vcmcifQ.tmKabP8zm9Jm01I8yzPHj-Wwn_Zs2HVNGxaCZGUPV4I
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.128 Electron/4.2.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBJvAIr4K1rvFNjfw
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US

------WebKitFormBoundaryBJvAIr4K1rvFNjfw
Content-Disposition: form-data; name="content"


------WebKitFormBoundaryBJvAIr4K1rvFNjfw--

When I setup the same POST multipart/form via the Insomnia rest client, the request and headers looks like:

POST /bundle/fbc173e8-81ca-4c2c-a32f-de6ccd337b99/resource/insomnia/MAT_001.mp3 HTTP/1.1
Host: 127.0.0.1:44151
User-Agent: insomnia/6.4.2
Content-Type: multipart/form-data; boundary=X-INSOMNIA-BOUNDARY
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0aGVkaWdpdGFsYmlibGVsaWJyYXJ5Lm9yZyIsImV4cCI6NDcxMDk0MzIzMCwiaWF0IjoxNTU3MzQzMjMwLCJzdWIiOiJFcmljIFB5bGUiLCJrZXkiOiJlcmljX3B5bGVAc2lsLm9yZyIsImVtYWlsIjoiZXJpY19weWxlQHNpbC5vcmcifQ.tmKabP8zm9Jm01I8yzPHj-Wwn_Zs2HVNGxaCZGUPV4I
Accept: /
Content-Length: 8399223

| (16 KB hidden)
| (16 KB hidden)
| (16 KB hidden)
| (16 KB hidden)
...
| (10.4 KB hidden)

  • We are completely uploaded and fine

< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Content-Length: 2
< Date: Wed, 08 May 2019 19:37:25 GMT

With Electron 1.7.11 I had been using request-promise-native (rp) successfully as follows (except that the traffic does not show up in the Network tab, which makes debugging the app painful!):

  const options = {
    method: 'POST',
    uri: fullUri,
    formData: {
      // Like <input type="file" name="content">
      name: filename,
      content: {
        value: fs.createReadStream(filePath),
        options: {
          filename
        }
      }
    },
    headers: {
      ...authHeader()
      /* 'content-type': 'multipart/form-data' */ // Is set automatically
    }
  };
  /* fetch does not support posting files as multipart/form-data
     https://github.com/electron/electron/issues/9684 */
  return rp(options);

But after merging to Electron 4.1.3 via electron-react-boilerplate (next branch) I also started getting a No content provided as file response:

error: "No content provided as file"
message: "400 - "No content provided as file""
name: "StatusCodeError"
options: {method: "POST", uri: "http://127.0.0.1:44151/bundle/fbc173e8-81ca-4c2c-a32f-de6ccd337b99/resource/MAT_001.mp3", formData: {…}, headers: {…}, callback: ƒ, …}
response: IncomingMessage {_readableState: ReadableState, readable: false, _events: {…}, _eventsCount: 3, _maxListeners: undefined, …}
statusCode: 400
stack: "StatusCodeError: 400 - "No content provided as file"↵    at new StatusCodeError (C:\Users\PyleE\Documents\repos\ubsicap\dbl.local.electron-upgrade\node_modules\request-promise-core\lib\errors.js:32:15)↵    at Request.plumbing.callback (C:\Users\PyleE\Documents\repos\ubsicap\dbl.local.electron-upgrade\node_modules\request-promise-core\lib\plumbing.js:104:33)↵    at Request.RP$callback [as _callback] (C:\Users\PyleE\Documents\repos\ubsicap\dbl.local.electron-upgrade\node_modules\request-promise-core\lib\plumbing.js:46:31)↵    at Request.self.callback (C:\Users\PyleE\Documents\repos\ubsicap\dbl.local.electron-upgrade\node_modules\request\request.js:121:22)↵    at Request.emit (events.js:182:13)↵    at Request.<anonymous> (C:\Users\PyleE\Documents\repos\ubsicap\dbl.local.electron-upgrade\node_modules\request\request.js:978:14)↵    at Request.emit (events.js:187:15)↵    at IncomingMessage.<anonymous> (C:\Users\PyleE\Documents\repos\ubsicap\dbl.local.electron-upgrade\node_modules\request\request.js:929:12)↵    at IncomingMessage.emit (events.js:187:15)↵    at endReadableNT (_stream_readable.js:1092:12)"
__proto__: Error```

@hugomrdias
Copy link

@MarshallOfSound can you please re-open this ? This still happens in electron 6

@Soltus
Copy link

Soltus commented Apr 19, 2024

We are no longer implementing bugfixes for versions of Electron <= , so I'm going to close this issue but if it is still persisting in more recent versions of Electron we can certainly reopen it!1.7.x

FormData is not defined in electron v31 alpha

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants