如何将 react-native 图片从 expo-image-picker 上传到使用 multer 的 Express.js 后端

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

正如标题所说,我正在尝试使用 expo-image-picker 和 express.js 后端上传图片

展会代码:

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);
}

快递编码

路由器:

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)

更新照片功能:

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)
  }
}

我得到的错误是

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)

这很可能意味着 object 未被传递或无法正确解析。

当我测试使用 Postman 仅通过后端上传图片时一切正常。 邮递员预设:

如何解决这个问题?

不要使用 axios 进行文件上传,因为您需要从本机文件系统读取图像。您可以使用 Expo 的 FileSystem 模块中的 uploadAsync()Documentation Here

在您的情况下,函数调用将是:

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'
    });
  }
}

顺便说一句,请避免使用 localhost,因为该应用可能 运行 在设备或模拟器上运行,而 localhost 将是设备本身,而不是您的网络服务器。通过环境变量传递 API 端点。更多信息 here。在开发过程中使用 dotenv 之类的东西来加载变量。