如何使用 fetch 从 React Native (expo) 将图像上传到 Node js 服务器

问题描述 投票:0回答:3

我没有在服务器端接收数据。有时我将数据作为对象获取。我尝试了不同的方法,但图像上传失败。下面是我的代码。我尝试了不同的方法,但结果是相同的图像文件夹保持为空,就像使用 multer 中间件

使用此片段显示图像

<TouchableHighlight
  style={[
    styles.profileImgContainer,
    { borderColor: "#4632a1", borderWidth: 1 },
  ]}
  onPress={openImagePickerAsync}
>
  <Image source={{ uri: selectedImage.localUri }} style={styles.thumbnail} />
</TouchableHighlight>

这是图像选择器部分

function PickImage() {
  let [selectedImage, setSelectedImage] = useState("");
  let 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 === true) {
      return;
    }

    setSelectedImage({ localUri: pickerResult.uri });
  };
}

获取 API 调用

async function upload() {
  const data = new FormData();
  data.append("image", {
    uri: selectedImage.uri,
    name: selectedImage.title,
    type: selectedImage.type,
  });

  const setting = {
    method: "POST",
    headers: {
      "Content-Type": "multipart/form-data;",
    },
    body: data,
  };
  try {
    const fetchResponse = await fetch(url, setting);
    const data = await fetchResponse.json();
    alert(data);
  } catch (e) {
    alert(e);
  }
}

服务器端代码

app.post("/users", upload.single("image"), async (req, res) => {
  console.log(req.body.file);
  console.log(req.body);
  const img = req.body.image;
  if (!img) {
    console.log("no image");
  }

  res.send({ congrats: "data recieved" });
});
react-native express expo multer
3个回答
1
投票

首先,

ImagePicker
不返回标题和mimeType。将状态更新逻辑改成这样

setSelectedImage({
  uri: result.uri,
  name: 'SomeImageName.jpg',
  type: 'image/jpg',
});

还将你的上传功能更改为此,(我最喜欢的编写 POST 请求的方式)

async function upload() {
  try {
    const data = new FormData();
    data.append("image", selectedImage);

    await fetch(URL_Endpoint, {
      method: "POST",
      body: data,
    });
  } catch (error) {
    console.log(error);
  }
}

其次,在服务器端,这样使用

您可以通过两种方式管理文件

1.) 磁盘存储

像这样定义 multer 配置

const express = require("express");
const app = express();
const multer = require("multer");

const storage = multer.diskStorage({
  destination: "./uploads/",
  filename: function (req, file, cb) {
    cb(null,  "SomeImage" + "." + file.originalname.split(".").pop());
  },
});

const diskStorage = multer({ storage: storage });

然后,

app.post("/users", diskStorage.single("image"), async (req, res) => {
  try {
    console.log(req.file); // File which is uploaded in /uploads folder.
    console.log(req.body); // Body
    res.send({ congrats: "data recieved" });
  } catch (error) {
    res.status(500).send("Error");
  }
});

2.) 内存存储

像这样定义 multer 配置

const express = require("express");
const app = express();
const fs = require("fs");
const multer = require("multer");

const memoryStorage = multer({
  storage: multer.memoryStorage(),
});

然后,

app.post("/users", memoryStorage.single("image"), async (req, res) => {
  try {
    console.log(req.file);
    console.log(req.body);

    // Here you will have to save it manually

    const DirName = `./uploads`;
    let URL = `./uploads/SomeImage.` + req.file.originalname.split(".").pop();

    fs.mkdir(DirName, { recursive: true }, async (err) => {
      if (err) {
        return res.status(500).send("Some Error");
      } else {
        fs.writeFile(URL, req.file.buffer, "ascii", function (err) {
          if (err) {
            return res.status(500).send("Some Error");
          } else {
            res.send({ congrats: "data recieved" });
          }
        });
      }
    });
  } catch (error) {
    res.status(500).send("Error");
  }
});

0
投票

我尝试了不同的方法通过 fetch 和 axios API 发送我的文件,但是 multer 无法找到我的图像 uri,因为它接受文件,因此您可以简单地 stringfy 图像的 uri 并将其发送到您的 Nodejs 服务器,而不是进入这些内容

axios API

const formData=new FormData()
  var imageJSON = {
    imageName:new Date().getTime()+"_profile",
    avatar:selectedImage,
    name:name,
    email:email,
    SocietyCode:sCOde,
    password:Password
  }

  formData.append('image', JSON.stringify(imageJSON))

  axios.post('http://localhost:3000/users',formData,{
    headers:{
      Accept: 'application/json',
      'Content-Type':'multipart/form-data'
    }
  }).then((responseData) => {
    console.log("before",responseData.data)
      
    })
    .catch((error) => {
      alert(error)
      console.log("ERROR " + error.message)
    });

节点服务器端代码

router.post('/users', upload.single('avatar'), async (req,res)=>{
      
        formData =await req.body;
        var userJSON =await JSON.parse(formData.image);
    
  const avatar =await Buffer.from(userJSON.avatar, "utf-8");

  delete userJSON.avatar
userJSON.avatar=avatar
console.log(userJSON)


 const user= new Users(userJSON)
        try{

          
            await user.save()
            res.send({'message':'Registeration Successfull'})

        }
        catch(e){
            res.send({'response':'registeration failed'})
            console.log(e)
        }
          
      })

0
投票

这个答案复制粘贴我的代码,以防有人需要它以供将来参考:

App.js

import { useState } from "react";
import { Button, Image, ScrollView, View } from "react-native";
import { launchImageLibrary } from 'react-native-image-picker';
import RNFetchBlob from "rn-fetch-blob";


async function add_images(setImages) {

  const images = await launchImageLibrary({ mediaType: 'photo', selectionLimit: 0 });

  if (images.didCancel)
    return

  setImages(val => {
    let copy_val = [...val]

    images.assets.forEach((item) => {
      copy_val.push({ uri: item.uri, filename: item.fileName })
    })

    return copy_val
  });

}

async function upload_images(images) {

  let data = []
  images.forEach((item, index) => {
    data.push({ name: 'images_data', filename: item.filename, data: RNFetchBlob.wrap(item.uri) })
  })

  // you may have to use another route instead of localhost
  RNFetchBlob.fetch('POST', 'localhost:3000/upload_images', { 'Content-Type': 'multipart/form-data' }, data);
}

export default function App() {

  const [images, setImages] = useState([]) // array of URIs
  
  return (<>

    <View style={{ flexDirection: 'row', justifyContent: 'space-evenly', marginVertical: 50 }}>
      <Button title="Add Images" onPress={() => { add_images(setImages) }} />
      <Button title="Clear Images" onPress={() => { setImages([]) }} />
      <Button title="Upload Images" onPress={() => { upload_images(images) }} />
    </View>

    <ScrollView horizontal={true}>
      {
        images.map((item, index) => {
          return (<Image key={index} style={{ height: 400, width: 400 }} source={{ uri: item.uri }} />)
        })
      }
    </ScrollView>

  </>)
}

node.js

// import fs from 'fs';
import multer from "multer";
import express from 'express';
const server = express();

var upload = multer({ dest: 'uploads/' });

server.post('/upload_images', upload.array('images_data'), (req, res) => {
    console.log(req.files);
    
    // req.files.forEach(item => {
    //     fs.renameSync(item.path, item.destination + item.originalname)
    // })
});

const PORT = 3000
server.listen(PORT, () => {
    console.log(`listening at ${PORT} ...`);
});
© www.soinside.com 2019 - 2024. All rights reserved.