React Native Expo: Network error on android

Drunken Daddy picture Drunken Daddy · Jan 13, 2021 · Viewed 7.7k times · Source

I'm using axios in my app. When I make a post request for the very first time after opening the app, it is failing with the following error. From second time onwards, it works without any issue.

Network Error
- node_modules/axios/lib/core/createError.js:15:17 in createError
- node_modules/axios/lib/adapters/xhr.js:81:22 in handleError
- node_modules/event-target-shim/dist/event-target-shim.js:818:20 in EventTarget.prototype.dispatchEvent
- node_modules/react-native/Libraries/Network/XMLHttpRequest.js:600:10 in setReadyState
- node_modules/react-native/Libraries/Network/XMLHttpRequest.js:395:6 in __didCompleteResponse
- node_modules/react-native/Libraries/vendor/emitter/EventEmitter.js:189:10 in emit
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:416:4 in __callFunction
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:109:6 in __guard$argument_0
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:364:10 in __guard
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:108:4 in callFunctionReturnFlushedQueue
* [native code]:null in callFunctionReturnFlushedQueue

I'm running on a real android device connecting to a real server by http://my_ip:my_port/. Same post request I tried by creating a Native android project in kotlin, and it is working without any issue

Here is my code:

const upload = () => {
    setAnalyzing(true);

    axios.post(URL_PREDICT, formBody(), {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    }).then(handleSuccess)
      .catch(handleFail);
  }

  const formBody = () => {
    const photo = {
      uri: image,
      type: 'image/jpeg',
      name: 'photo.jpg',
    };
    const form = new FormData();
    form.append("file", photo);
    return form;
  };

  const handleFail = (error) => {
    console.log(error)
    console.log(error?.response?.data);
    setAnalyzing(false);
    toggle();
    alert("ERROR " + error);
  };

  const handleSuccess = response => {
    console.log('success...');
    setAnalyzing(false);
    toggle();
    console.log(response);
    navigation.navigate('Result', response);
  };

Any idea whats causing this?

Answer

gmj picture gmj · Jan 19, 2021

I think you are using expo-image-picker.

There are two independent issues at action here. Let’s say we get imageUri from image-picker, then we would use these following lines of code to upload from the frontend.

const formData = new FormData();
formData.append('image', {
 uri : imageUri,
 type: "image",
 name: imageUri.split("/").pop()
});

The first issue is with the imageUri itself. If let’s say photo path is /user/.../path/to/file.jpg. Then file picker in android would give imageUri value as file:/user/.../path/to/file.jpg whereas file picker in iOS would give imageUri value as file:///user/.../path/to/file.jpg.

The solution for the first issue is to use file:// instead of file: in the formData in android.

The second issue is that we are not using the proper mime-type. It is working fine on iOS but not on Android. What makes this worse is that the file-picker package gives the type of the file as “image” and it does not give proper mime-type.

The solution is to use proper mime-type in the formData in the field type. Ex: mime-type for .jpg file would be image/jpeg and for .png file would be image/png. We do not have to do this manually. Instead, you can use a very famous npm package called mime.

The final working solution is:

import mime from "mime";

const newImageUri =  "file:///" + imageUri.split("file:/").join("");

const formData = new FormData();
formData.append('image', {
 uri : newImageUri,
 type: mime.getType(newImageUri),
 name: newImageUri.split("/").pop()
});