React Native Expo: Network error on android

23.5k Views Asked by At

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?

6

There are 6 best solutions below

1
Honey On BEST ANSWER

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()
});
4
Muhammad Numan On

Solution 1

Make Sure "http://" is in your URL Address .

  1. change from localhost to your ip
  2. add http://

http://192.168.43.49:3000/user/

Solution 2

I faced same issue, it happens in Android, but works well in IOS. I guess this issue about Flipper Network.

For while, I commented

initializeFlipper(this, getReactNativeHost().getReactInstanceManager())

in this file /android/app/src/main/java/com/{your_project}/MainApplication.java

Solution 3

Whoever is still struggling with this issue. it's happening because of Flipper network plugin. I disabled it and things work just fine.

My workaround to make this work is commenting out line number 43

38      NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
39      NetworkingModule.setCustomClientBuilder(
40          new NetworkingModule.CustomClientBuilder() {
41            @Override
42            public void apply(OkHttpClient.Builder builder) {
43      //        builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
44            }
45          });
46      client.addPlugin(networkFlipperPlugin);

in this file android/app/src/debug/java/com/**/ReactNativeFlipper.java

Solution 4

don't need to add Access-Control-Expose-Headers.

Need this:

                headers:{
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Accept': 'application/json'}
            }

And I adjust your server,it works.

0
Andy Puneri On

If someone doesn't like the upvoted answer or is still facing the issue, then my answer might help. Make sure your emulator/device time is same as real world time to avoid certificate validation error, otherwise manually set the correct time and reload the app.

0
acilveti On

I had the same problem when trying to send an API request from an react native application using expo in a emulator to my rust actix web server. After spending several hours into the issue and not being able to find the way to fix it, I found the solution in ngrok. It makes a tunnel from your local server to open web, so basically yo can call from your RN app to your api endpoint as if it would not be running in your localhost.

The error was fixed, instantly. Hope it helps, even if I am aware that is not a fix, but a workaround to your problem.

1
Abi B On

In case anyone is having trouble with this again.. I found that for android the ip needed to be 10.0.2.2 but for ios it needed to be 127.0.0.1.

The code below allows you to set them independently:

import { Platform } from 'react-native';

const LOCALHOST = Platform.OS === 'ios' ? 'http://127.0.0.1:8000' : 'http://10.0.2.2:8000';
export const API_BASE_URL = LOCALHOST + '/api/v1/';
0
Isaac Frank On

I'm still experiencing this issue as of Nov 2023, and none of the solutions here works.

Using FileSystem's uploadAsync works perfectly, only downside to this is that it doesn't allow multiple file upload which is a deal breaker for me.

npx expo install expo-file-system

if you are only uploading a single file, then you could use this snippet


import {uploadAsync} from "expo-file-system"
import axios from "axios"

let url = "" // your endpoint
let image = {} //imagePickerResult;
let sendData = {} // Plain object
let formData = new FormData(); // sendData  keys and values appended to formdata plus the image
 
if (Platform.OS == "android") {
    let res = await uploadAsync(url, image.uri, {
        fieldName: "nameOfField", 
        httpMethod: "PATCH", 
        mimeType: "image/*", 
        uploadType: FileSystemUploadType.MULTIPART, 
        headers: {
            // access token bearears auth and what-not
        }, 
        parameters: sendData // This would be the BODY of the request
    })
    return res
} else {
    let res = await axios.patch(url, formData);

    return res
}