简体   繁体   中英

How to upload react-native image from expo-image-picker to Express.js backend that is using multer

as title says, I am trying to upload picture using expo-image-picker and express.js backend

Expo code:

const openImagePickerAsync = async () => {
  let permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
  if (permissionResult.granted === false) {
    alert("Permission to access camera roll is required!");
    return;
  }
  let pickerResult = await ImagePicker.launchImageLibraryAsync();
  const dataa = Object.values(pickerResult);
  var data = new FormData();
  data.append('image', {
    path: dataa[2], //image uri
    originalname: "profilePic" + userId + ".jpg",
    type: "image/jpg",
    fieldname: "demo_image"
  })
  console.log(data)
  const uploadImage = await axios.post(`http://localhost:8000/api/upload/picture/` + userId, data);
}

Express code

Router:

var multer = require("multer")
var storage = multer.diskStorage({
  destination: function(req, file, cb) {
    console.log(file)
    cb(null, './controllers/assets/profilePic/');
  },
  filename: function(req, file, cb) {
    console.log(file)
    cb(null, file.originalname);
  }
});
var upload = multer({
  storage: storage
}).single("demo_image");
router.route("/upload/picture/:userId").post(upload, UserController.updatePhoto)

updatePhoto function:

static updateGamePhoto = async (req, res) => {
  try {
    const query = await GamMdl.find({
      game_id: req.params.gameId
    })
    console.log(req.file)
    if (query.length > 0) {
      //get file route
      //get route to db
      const queryy = await GamMdl.updateOne({
        game_id: req.params.gameId
      }, {
        picture: req.file.originalname
      })
      console.log(queryy)
      res.send("1")
    } else {
      //vymaz file
      fs.unlinkSync(req.file.path)
      res.send("0")
    }
  } catch (error) {
    console.log(error)
  }
}

The error I am getting is

2022-04-10T18:17:29.165105+00:00 app[web.1]: undefined
2022-04-10T18:17:29.165435+00:00 app[web.1]: TypeError: Cannot read properties of undefined (reading 'originalname')
2022-04-10T18:17:29.165436+00:00 app[web.1]:     at updatePhoto (/app/controllers/userController.js:166:119)
2022-04-10T18:17:29.165436+00:00 app[web.1]:     at runMicrotasks (<anonymous>)
2022-04-10T18:17:29.165439+00:00 app[web.1]:     at processTicksAndRejections (node:internal/process/task_queues:96:5)

Which most likely means, that object is not being passed or is unable to be parsed correctly.

When I test uploading image only with backend using Postman all works well. Postman preset:

邮递员预设

How to fix this?

Don't use axios for file upload because you need to read the image from the native filesystem. You can use uploadAsync() from the FileSystem module from Expo. Documentation Here

In your case the function call would be:

const openImagePickerAsync = async () => {
  let permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
  if (permissionResult.granted === false) {
    alert("Permission to access camera roll is required!");
    return;
  }
  let pickerResult = await ImagePicker.launchImageLibraryAsync();
  if (!pickerResult.cancelled) {
    const uploadResult = await FileSystem.uploadAsync('http://localhost:8000/upload/picture/1', pickerResult.uri, {
      httpMethod: 'POST',
      uploadType: FileSystemUploadType.MULTIPART,
      fieldName: 'demo_image'
    });
  }
}

By the way, avoid using localhost since the app may run on a device or emulator, and localhost would be the device itself instead of your webserver. Pass the API endpoint via environment variables. More info here . Use something like dotenv to load variables during development.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM