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

missing boundary in Content-Type for multipart posts #746

Closed
bdefore opened this issue Sep 24, 2015 · 21 comments
Closed

missing boundary in Content-Type for multipart posts #746

bdefore opened this issue Sep 24, 2015 · 21 comments

Comments

@bdefore
Copy link

bdefore commented Sep 24, 2015

I'm attempting to use superagent to upload files to Cloudinary. I have the following code:

    const settings = {
      CLOUDINARY_API_KEY: {REDACTED},
      CLOUDINARY_ACCOUNT_NAME: {REDACTED},
      CLOUDINARY_UPLOAD_PRESET: {REDACTED}
    };

    const req = request.post(`https://api.cloudinary.com/v1_1/${settings.CLOUDINARY_ACCOUNT_NAME}/image/upload`);
    files.forEach((file) => {
      req.attach(file.name, file);
    });
    req.set('Accept', 'application/json');
    req.set('X-Requested-With', 'XMLHttpRequest');
    req.attach('api_key', settings.CLOUDINARY_API_KEY);
    req.attach('timestamp', Date.now() / 1000);
    req.attach('upload_preset', settings.CLOUDINARY_UPLOAD_PRESET);
    req.type('multipart/form-data');
    req.end((err, res) => {
      if (err) {
        console.log('error', err);
      } else {
        console.log('success', res);
      }
    });

Running on localhost, I'm getting the error from their API:

XMLHttpRequest cannot load https://api.cloudinary.com/v1_1/dmzafaonc/image/upload. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3030' is therefore not allowed access. The response had HTTP status code 502.

But I believe this is a red herring, since I'm able to upload successfully with the Dropzone library, loaded from a local dropzone.js file. It also gives an error response if I comment out the file attachments - it correctly tells me that a parameter is missing.

This led me to look into the request in Chrome Inspector:

Request Headers:

Accept:application/json
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Content-Length:31756
Content-Type:multipart/form-data
DNT:1
Host:api.cloudinary.com
Origin:http://localhost:3030
Pragma:no-cache
Referer:http://localhost:3030/drop
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.99 Safari/537.36
X-Requested-With:XMLHttpRequest

Request Payload:

------WebKitFormBoundary9uDkePsFayAfLf8a
Content-Disposition: form-data; name="birthdaybeer_400.jpg"; filename="undefined"
Content-Type: image/jpeg


------WebKitFormBoundary9uDkePsFayAfLf8a
Content-Disposition: form-data; name="api_key"


------WebKitFormBoundary9uDkePsFayAfLf8a
Content-Disposition: form-data; name="timestamp"


------WebKitFormBoundary9uDkePsFayAfLf8a
Content-Disposition: form-data; name="upload_preset"


------WebKitFormBoundary9uDkePsFayAfLf8a--

Note the Content-Type field, which is lacking the boundary. That's the only difference I can see from the corresponding dropzone.js request and the superagent one: Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzg196Oz74o5Y3jvp

I cannot set the Content-Type manually with the boundary because it is generated by superagent.

Any ideas?

@bdefore
Copy link
Author

bdefore commented Sep 24, 2015

A similar discussion ongoing for POSTman here: postmanlabs/postman-app-support#576

@bdefore
Copy link
Author

bdefore commented Sep 24, 2015

As a workaround, I got this to work, with the proper Content-Type set, using FormData:

    const req = request.post(`https://api.cloudinary.com/v1_1/${settings.CLOUDINARY_ACCOUNT_NAME}/image/upload`);

    const data = new FormData();
    files.forEach((file) => {
      data.append('file', file);
    });
    data.append('api_key', settings.CLOUDINARY_API_KEY);
    data.append('timestamp', Date.now() / 1000);
    data.append('upload_preset', settings.CLOUDINARY_UPLOAD_PRESET);

    req.send(data);
    req.end((err, res) => {
      if (err) {
        console.log('error', err);
      } else {
        console.log('success', res);
      }
    });

@philippTheCat
Copy link

@bdefore can you explain how you got it to work? In your example you're not setting the proper Content-Type which you said was needed for it to work correctly.

@bdefore
Copy link
Author

bdefore commented Nov 23, 2015

@pharno still using that workaround

@jsdario
Copy link

jsdario commented Mar 1, 2016

@bdefore +1. Same problem here.

@marcuswhit
Copy link

+1 Same problem

simula67 pushed a commit to simula67/grommet that referenced this issue Apr 26, 2016
Also workaround potential superagent issue at ladjs/superagent#746
@meenalt
Copy link

meenalt commented May 4, 2016

+1 on this issue.

I can't use FormData in React, so the workaround solution doesn't work either :(. Anybody have any other suggestions?

@meenalt
Copy link

meenalt commented May 4, 2016

I found that uploading files without specifying the Content-Type worked for me. In the request, I saw that Superagent was able to determine that the Content-Type was multipart/form-data and appended the correct boundary. It worked successfully.

@marcuswhit
Copy link

@meenalt Why can't you use FormData in React? I ended up getting this working using the following:

let data = new FormData();
data.append('file', file, file.name);

superagent
    .post('url')
    .send(data)
    .end((ex, result) => {

    });

@tengla
Copy link

tengla commented May 13, 2016

You should probably use field for non-file data. Like req.field('name', 'John Doe')

@Webbrother
Copy link

The same problem.
I use @athlite approach. Not sure which one is right.
Can anybody explain what is right way to set 'multipart/form-data' manually to request? Thanks.

@kornelski
Copy link
Contributor

I think the solution is to never set content-type manually for multipart.

@Webbrother
Copy link

@pornel thank you! Could you please explain in details what is the correct way to upload file with using 'superagent' and without manual setting of 'content-type'?

@kornelski
Copy link
Contributor

superagent.post(url)
   .attach('field_name', file_object) // file_object can be File or Blob
   .then(result => {}) // .end() works too

@cvkkumar
Copy link

@pornel Wow!! Thank YOU! I was totally dumbstruck for a few hours.

@melkishengue
Copy link

Thank you so much @pornel You saved my day!!

@pjisha
Copy link

pjisha commented Feb 7, 2017

Thank you so much @pornel, wow !!

@ymma
Copy link

ymma commented Feb 27, 2017

req.set('enctype', 'multipart/form-data')

@Evgeny-Mamaev
Copy link

@ymma Thank you so much. Once I've added req.set('enctype', 'multipart/form-data') to my request, it started to define correct boundaries of the file.

@rip3rs
Copy link

rip3rs commented May 29, 2017

@ymma that worked perfectly.

I am not very savvy with headers and stuff, would you mind explaining why this works like this?

Best,
Joe

@patrickleemsantos
Copy link

I tried setting content type to undefined and it works

.set('Content-Type', undefined)

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

No branches or pull requests