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

Axios don't send form data in react-native #1321

Closed
corujoraphael opened this Issue Jan 25, 2018 · 28 comments

Comments

Projects
None yet
@corujoraphael
Copy link

corujoraphael commented Jan 25, 2018

I've try to send a form data with axios but i can't, in chrome dev tools no content appears in the request. Making a same request via postman the API response normally.

  (newData) => {
   const data = new FormData();
   data.append('name', 'raphael');
   data.append('file', {
       uri: newData.image.path,
       type: 'image/jpeg',
       name: 'teste'
   });
   return axios.post(`${constants.development.URL_API}/file`, data, 
       headers: {
           'Content-Type': 'multipart/form-data',
       },
   })`
@pedpess

This comment has been minimized.

Copy link

pedpess commented Jan 30, 2018

@corujoraphael Out of curiosity, was this request working earlier?

@emilyemorehouse

This comment has been minimized.

Copy link
Member

emilyemorehouse commented Feb 11, 2018

@corujoraphael I'm not sure that your code runs as-is. The config where you specify your headers should be an object, but it's missing a curly brace:

(newData) => {
  const data = new FormData();
  data.append('name', 'raphael');
  data.append('file', {
    uri: newData.image.path,
    type: 'image/jpeg',
    name: 'teste'
  });

  return axios.post(
    `${constants.development.URL_API}/file`,
    data, 
    { 
      headers: {
        'Content-Type': 'multipart/form-data',
      }
    },
  )
}

Since this issue hasn't received a response and this doesn't look like an Axios bug based on the info we have, I'm closing this issue.

If you need further assistance debugging your code, please post on Stack Overflow, Gitter, or comment again on this issue.

Thanks!

@Ernie6711

This comment has been minimized.

Copy link

Ernie6711 commented Feb 20, 2018

@emilyemorehouse , I met the same problem using React Native FormData

let s = JSON.stringify({ uri: localUri, name: filename, type: type });
let formData = new FormData();
formData.append('ph0t0', s);

axios.post("http://10.0.1.2:8888/uploadphoto", {
        method: "POST",
        headers: {
                'Content-Type': 'multipart/form-data; charset=utf-8; boundary="another cool boundary";'
        },
        body: formData,
}).then((resp) => {
        console.log(resp);
}).catch(err => {
        console.log(err);
});

Expect some key:value pairs exist in MultipartForm, Form, or PostForm

2018/02/20 18:25:31.740 [W] [photo.go:411] req.MultipartForm: nil
2018/02/20 18:25:31.740 [W] [photo.go:412] req.Form: map[]
2018/02/20 18:25:31.740 [W] [photo.go:413] req. PostForm: map[]
2018/02/20 18:25:31.740 [W] [photo.go:410] req: &{POST /uploadphoto/dialog/57120e8951c643ab42a8c19f/000000000000000000000001 HTTP/1.1 1 1 map[Content-Type:[application/json;charset=utf-8] User-Agent:[okhttp/3.6.0] Accept:[application/json, text/plain, /] Content-Length:[419] Connection:[Keep-Alive] Accept-Encoding:[gzip] Cookie:[lang=zh-TW; PVsessionID=db9a21d63b2d0ea47b68fa8755bd87e2]] 0xc420e3cb80 419 [] false 10.0.1.2:8888 map[] map[] map[] 10.0.1.3:46904 /uploadphoto/dialog/57120e8951c643ab42a8c19f/000000000000000000000001 0xc420e3cb40}
2018/02/20 18:25:31.740 [E] [photo.go:425] [UploadPhotos] err: request Content-Type isn't multipart/form-data

Version info
axios: 0.16.2
expo: 25.0.0
react: 16.2.0
react-native: 0.52.0

@giladno

This comment has been minimized.

Copy link

giladno commented Mar 9, 2018

This bug still happens with latest axios, why was this closed?

@emilyemorehouse

This comment has been minimized.

Copy link
Member

emilyemorehouse commented Mar 9, 2018

If someone can provide a reproducible example, I'm happy to open this back up.

@Ernie6711 it looks like you have an error in your code -- I don't think you should stringify the file data before appending it to your form data. Also, the arguments for axios.post are axios.post(url[, data[, config]])

Here's an example based on your code:

const file ={ uri: localUri, name: filename, type: type};
const formData = new FormData();
formData.append('file', s);

const config = {
        headers: {
                'Content-Type': 'multipart/form-data; charset=utf-8; boundary="another cool boundary";'
        }
};

axios.post("http://10.0.1.2:8888/uploadphoto", formData, config).then((resp) => {
        console.log(resp);
}).catch(err => {
        console.log(err);
});
@giladno

This comment has been minimized.

Copy link

giladno commented Mar 9, 2018

@emilyemorehouse please check wireshark traces. The data is uploaded but it does NOT use proper form-data encoding. The above example can reproduce the problem. Again - the request is being sent successfully but is it badly encoded.

POST /myserver HTTP/1.1
Content-Type: multipart/form-data

_parts=USERX%2Cusername&_parts=FILE1%2C%5Bobject%20Object%5D
@emilyemorehouse

This comment has been minimized.

Copy link
Member

emilyemorehouse commented Mar 9, 2018

I have a local client and server example for file uploads, albeit outside of the React Native environment, that works and is properly encoded. The example above isn't really reproducible since it relies on variables and a server that I don't have access to.

My guess is that if there's something incorrect with the upload, it's because the data appended to the form data object is not valid.

@giladno

This comment has been minimized.

Copy link

giladno commented Mar 9, 2018

@emilyemorehouse File uploads work perfectly in a browser environment, they only fail on react native. As you mentioned yourself - your tests were outside of react native environment, I would start there :)

Try a simple file upload in react native and simply check the wireshark traces, you don't even need a working server...

@duongtranpyco

This comment has been minimized.

Copy link

duongtranpyco commented Mar 16, 2018

I got the same, Axios does not on react native

@giladno

This comment has been minimized.

Copy link

giladno commented Mar 17, 2018

@duongtranpyco I've removed axios from my project, I wrote my own simple class instead, enjoy!

P.S. If you mainly sending JSON, modify the code. In my case, the server usually expects a form.

const request = async ({url, method = 'GET', params, body, responseType = 'json', headers = {}})=>{
    const escape = (data, encode = encodeURIComponent)=>Object.keys(data||{}).reduce((pairs, key)=>{
        for (let value of [].concat(data[key]))
            pairs.push([`${key}`, `${value}`]);
        return pairs;
    }, []).map(pair=>pair.map(encode).join('=')).join('&');

    if (Object.keys(params||{}).length)
        url += '?'+escape(params);
    if (method=='POST' && typeof body=='object')
    {
        if (body instanceof FormData)
            headers['Content-Type'] = 'multipart/form-data';
        else
        {
            body = escape(body);
            headers['Content-Type'] = 'application/x-www-form-urlencoded';
        }
    }
    let {statusCode, request: req} = await new Promise((resolve, reject)=>{
        let xhr = new XMLHttpRequest();
        xhr.open(method, url, true);
        xhr.withCredentials = true;
        xhr.responseType = {json: 'text'}[responseType]||responseType;
        xhr.onload = ()=>resolve({statusCode: xhr.status, request: xhr});
        xhr.onerror = ()=>reject(new TypeError('Network request failed'));
        xhr.ontimeout = ()=>reject(new TypeError('Network request timed out'));
        for (let key in headers)
            xhr.setRequestHeader(key, headers[key]);
        xhr.send(body||null);
    });
    if (statusCode<200 || statusCode>=400)
        throw new Error(`network request failed with ${statusCode}: ${url}`);
    switch(responseType)
    {
        case 'json':
            return JSON.parse(req.responseText);
        case 'text':
            return req.responseText;
        case 'request':
            return req;
    }
    return req.response;
};

request.get = (url, opt = {})=>request({...opt, url, body: null});
request.post = (url, ...args)=>request({...args[1]||{}, url, method: 'POST', body: args[0]});
@jlariza

This comment has been minimized.

Copy link

jlariza commented Apr 19, 2018

Hi, I am facing the same problem. Has anybody found a solution?

@Ernie6711

This comment has been minimized.

Copy link

Ernie6711 commented Apr 20, 2018

Second @giladno. Since I'm going forward on other parts, I use a workaround instead: write a specific function with fetch() when uploading images.

Tried before and neither stringifying the data or arguments affect the result. The server received the call but no data sent.

@jlariza

This comment has been minimized.

Copy link

jlariza commented Apr 24, 2018

@Ernie6711 apparently the headers are corrupted and that is why the server is unable to accept the form data. I implemented the workaround with fetch() and it worked with no problems.

@caciobanita

This comment has been minimized.

Copy link

caciobanita commented Jun 9, 2018

I did have the some problem in react-native.
The problem are not the Headers.
In web we can have for example:

let formData = new FormData()
formData.append('key', true // bool value)

but in react native the value for key must be string.

formData.append('key', 'true')

@brayanL

This comment has been minimized.

Copy link

brayanL commented Jul 4, 2018

I have the same issue on react native when I post to a url, as @giladno mentions, you should test in react native and you could verify the error that people report @emilyemorehouse. I report an error 14 days ago https://github.com/axios/axios/issues/1618, but nobody has responded, please describe in the readme of your library that you do not have support for axios on react native, so that many developers do not waste time..!

@emilyemorehouse

This comment has been minimized.

Copy link
Member

emilyemorehouse commented Jul 4, 2018

Y'all, I appreciate the direction but "just test a file upload in React Native" isn't that easy. I don't often work in React Native and it would take a decent amount of time to spin up a project with file uploads to test with.

I do have a simple POST with form data that works in React Native:

    const formData = new FormData();
    formData.append("data", true);

    const config = {
      headers: {
        "Content-Type": "multipart/form-data; charset=utf-8;"
      }
    };

    axios.post(URL, formData, config).then(
      response => {
        console.log({ response });
      },
      error => {
        console.log({ error });
      }
    );

true gets stringified when sent to the server, which is interesting.

That said, if anyone can provide an example that I can easily spin up, I'm happy to look into it more.

@shushuy

This comment has been minimized.

Copy link

shushuy commented Aug 14, 2018

@corujoraphael how did you solved this?

@shushuy

This comment has been minimized.

Copy link

shushuy commented Aug 15, 2018

I added a type inside the image object like "Image.type='image/png" just before append and also changed the content type to "Content-Type":"multipart/form-data" :

        image.type='image/png'
        formData.append("resource", image);
        return axios
          .post('yourBAckendUrl', formData, {
            headers: {
              Authorization: "yourTokenHere",
              "Content-Type": "multipart/form-data"
            }
          })

Hope this help someone.

@kodayashi

This comment has been minimized.

Copy link

kodayashi commented Aug 31, 2018

I was unable to get this to work as well, I'm trying to PUT multipart/form-data to S3 (video). Using the type option didn't help. The multipart/form-data header doesn't seem to be in the PUT request:

      const data = new FormData();
      data.append('video', {
          uri: 'file:///<path_to_video_on_iphone.mov',
          type: 'video/quicktime',
          name: 'video.mov',
      });
      response = yield call(() => {
        return api.put(url, data, {
          headers: {
              'Content-Type': 'multipart/form-data',
          },
          transformRequest: [
            (data, headers) => {
                delete headers.common.Authorization;
                return data;
            }
          ]
        });
      });
@vampyar

This comment has been minimized.

Copy link

vampyar commented Sep 13, 2018

For this case use fetch :D

var data = new FormData();  
data.append('my_photo', {  
  uri: filePath, // your file path string
  name: 'my_photo.jpg',
  type: 'image/jpg'
}

fetch(path, {  
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'multipart/form-data'
  },
  method: 'POST',
  body: data
});
@verybluebot

This comment has been minimized.

Copy link

verybluebot commented Sep 27, 2018

in axios version 0.18.0 having same issue.
axios removes internally the header Content-Type if there is no body on the post, put etc for some reason when creating FormData the body remains empty..
this is my code:

const sendFormData = images => {
   // images is an array of base64 images (strings)
    const formData = new FormData();
    images.forEach((img, i) => {
        formData.append('file', img);
        formData.append('name', `${type}-${i + 1}`);
    });

    config.headers = {
        .'Content-Type': 'multipart/form-data'
     };

     return axios.post(`http://someurl.com/api/upload-images`, formData, config)
            .then(response => {
               // handle success
            })
            .catch(err => {
                // handle err
     });
}

React Native version 0.55.3
this example code is not working. request body is empty and the Content-Type header is removed

@minhphung210

This comment has been minimized.

Copy link

minhphung210 commented Oct 26, 2018

i have same issues and my �body when i check in debug is string

screen shot 2018-10-26 at 11 12 10 am

and here my code

        const formData = new FormData();
        formData.append('photo', {
          uri: response.uri.replace('file://', ''),
          mineType: 'image/jpeg',
          fileType: 'image/jpg',
          type: 'image/jpg',
          name: 'test.jpg'
        });

        console.log('form data', formData);

         Axios({
           method: 'post',
           url: 'https://dev-host.luxstay.net/api/rooms/10740/photos',
           data: formData,
           headers: {
             Authorization: token,
             'Content-Type': 'multipart/form-data'
           }
         });

Update : An error occurred because the app was in debug mode. When i turn off debug mode , it worked

@vineethgeorge03

This comment has been minimized.

Copy link

vineethgeorge03 commented Nov 29, 2018

axios has a code in its xhr adapter
if (utils.isFormData(requestData)) { delete requestHeaders['Content-Type']; // Let the browser set it }
i guess in react-native it deletes the content-type header if you are sending multipart form data even if you set it in the code .
But I am not sure if commenting the line out would resolve your issue in react-native.

in axios version 0.18.0 having same issue.
axios removes internally the header Content-Type if there is no body on the post, put etc for some reason when creating FormData the body remains empty..
this is my code:

const sendFormData = images => {
   // images is an array of base64 images (strings)
    const formData = new FormData();
    images.forEach((img, i) => {
        formData.append('file', img);
        formData.append('name', `${type}-${i + 1}`);
    });

    config.headers = {
        .'Content-Type': 'multipart/form-data'
     };

     return axios.post(`http://someurl.com/api/upload-images`, formData, config)
            .then(response => {
               // handle success
            })
            .catch(err => {
                // handle err
     });
}

React Native version 0.55.3
this example code is not working. request body is empty and the Content-Type header is removed

@tkserver

This comment has been minimized.

Copy link

tkserver commented Dec 4, 2018

screen shot 2018-10-26 at 11 12 10 am

So what should it look like? I have object object as well.

@minhphung210

This comment has been minimized.

Copy link

minhphung210 commented Dec 4, 2018

@tkserver it's look like when you have a object and then you toString() it.

const a = {
  name: 'dasdasd'
}
console.log(a.toString());
@tkserver

This comment has been minimized.

Copy link

tkserver commented Dec 4, 2018

@tkserver it's look like when you have a object and then you toString() it.

const a = {
  name: 'dasdasd'
}
console.log(a.toString());

Perhaps I wasn't clear. Should the Request Payload show [object Object] when viewing the headers?

@Aman725

This comment has been minimized.

Copy link

Aman725 commented Dec 18, 2018

@tkserver if your debugger has network inspect enabled, it will override the react-native's FormData and will result in passing empty FormData object which will look like [Object object] in network inspect.
Try making request with turning off network inspect, hope this helps.

@tkserver

This comment has been minimized.

Copy link

tkserver commented Dec 18, 2018

Thanks Aman725, minhphung210 and all. When I use the code on a real device the upload works properly. It would seem this is related to the iOS simulator.

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