guss189
guss189

Reputation: 71

React Native (with expo) fetch with FormData Network error on Android only

When i try to do a fetch API call in POST with React native (expo SDK 37) using fetch and FormData, everything works perfectly on IOS but it makes a Network error on Android: [TypeError: Network request failed]. I have the same error (network error) if I use axios instead of fetch.

If I replace the formData with empty a {}, it works. I've checked on an emulator and on physical devices (with various Android versions), and i tried to play with headers but no result. And my API has a valide let's encrypt certificate

let url = 'https://my-prod-server/webservice';

let formData = new FormData();
formData.append('test1','test1');
formData.append('test2','test2');

let request = await fetch(url, {
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'multipart/form-data',
  },
  method: 'POST',
  body: formData,
})
.then(response => response.json())
.catch(error => console.log('API ERROR: ', error));

return request;

Upvotes: 7

Views: 8844

Answers (3)

eightyfive
eightyfive

Reputation: 4721

If all of the above fails, you likely need to increase your client_max_body_size in your nginx server block configuration:

server {
    client_max_body_size 10M;

It's 1M by default. Not enough for jpegs nowadays.

Upvotes: 1

alo
alo

Reputation: 21

This is still present in Expo 46 and was brought up in a Github Issue.

https://github.com/expo/expo/issues/8323#issuecomment-761675526

It's because Android requires the file.type to be more specific than iOS does.

iOS will accept 'image' but Android will expect 'image/png' (or whatever file extension your using)

 const uriArray = result.uri.split(".");
 const fileExtension = uriArray[uriArray.length - 1];  // e.g.: "jpg"
 const fileTypeExtended = `${result.type}/${fileExtension}`; // e.g.: "image/jpg"

data.append('file', {
        uri: result.uri,
        name: image_name,
        type: type: fileTypeExtended
});

The above block works with both iOS and Android and is gratefully copied from @olapiv in the Github thread above.

Upvotes: 2

Callback
Callback

Reputation: 93

I had the same issue while trying to post image using fetch and FormData on expo SDK 38. The requests were successful on iPhone while it failed with [TypeError: Network request failed] on Android. Upon further investigation, i found out that my requests were not reaching the server at all and issue seemed to be with using FormData only. The requests with FormData were probably timing out/rejected and resulting in the error. I wasted a lot of time searching for answers and trying to implement the solutions suggested but nothing helped, when I came across a post which mentioned XMLHttpRequest. I ended up using XMLHttpRequest instead of fetch in this particular case and it worked like a charm with the FormData on both Android device and iPhone.

Declare a function as follows and replace the values between < and > with appropriate values

function sendXmlHttpRequest(data) {
  const xhr = new XMLHttpRequest();

  return new Promise((resolve, reject) => {
    xhr.onreadystatechange = e => {
      if (xhr.readyState !== 4) {
        return;
      }

      if (xhr.status === 200) {
        resolve(JSON.parse(xhr.responseText));
      } else {
        reject("Request Failed");
      }
    };
    xhr.open("POST", <apiEndpoint>);
    xhr.setRequestHeader(<headerName>, <value>);
    xhr.send(data);
  });
}

Now somewhere in your code, create a new FormData object and append any relevant fields/info, then finally call the sendXmlHttpRequest function which will take care of the request.

const photoData = new FormData();
photoData.append("photo", {
  uri: <uri of the photo>,
  name: filename,
  type: "image/jpeg"
});

const response = await sendXmlHttpRequest(photoData);

Upvotes: 7

Related Questions