如何将图像从客户端发送到服务器节点 js react

时间:2021-03-25 10:35:12

标签: node.js reactjs

我正在尝试创建上传个人资料图片方法,帮助用户在网站上上传他们的个人资料图片,但我不知道如何将图像从客户端发送到服务器并将这些图像存储在 cloudinary 或 firebase 上。< /p>

我的路线如下所示: ProfileAPI.js

    const express = require("express");
    const router = express.Router();
    const { body, param } = require("express-validator");
    const { catchErrors } = require("../errors/errorHandlers");
    const multer = require('multer');
    const uuidv4 = require('uuid/v4');
    
    const upload_dir = './images';
    
    const storage = multer.diskStorage({
      destination: (req, file, cb) => {
        cb(null, upload_dir);
      },
      filename: (req, file, cb) => {
        cb(null, `${uuidv4()}-${file.filename.toLowerCase}`);
      }
    });
    
    const upload = multer({
      storage: storage,
      fileFilter: (req, file, cb) => {
        if (
          file.mimetype == 'image/png' ||
          file.mimetype == 'image/jpg' ||
          file.mimetype == 'image/jpeg'
        ) {
          cb(null, true);
        } else {
          cb(null, false);
          return cb(new Error('Only .png, .jpg and .jpeg format allowed!'));
        }
      }
    });
const {
  getUserProfile,
  getUsersPublicProfile,
  lookUpId,
  updateUserProfile,
  updateUserEmail,
  deleteUserProfile,
  // deleteUserSkill,
  addPlayersProfile,
  getCreatedPlayers,
  updatePlayersProfile,
  deleteUserCreatedPlayer,
} = require("./profilesController");
    
    router.post(
      "/upload",
      upload.single('profileImg'),
      updateUserProfile
    );

所以关键点是设置存储告诉哪里上传+上传文件过滤器,对吗?

还有将 `upload.single('profileImg') 的 route.post,对吗?该路由将包括我的 updateUserProfile 控制器,可在此处找到: profilesController.js

exports.updateUserProfile = async (req, res) => {
  const userId = req.session.passport.user.id;
  // This array will contain all the update functions to run.
  const updates = [];

  // If a gravatar url has not been generated, do it now.
  const pictureValue = gravatar.url(
    req.body.email,
    { s: "100", r: "pg", d: "retro" },
    true
  );

  const payload = {
    fullname: req.body.fullname,
    location: req.body.location,
    webpage: req.body.webpage,
    linkedin: req.body.linkedin,
    institution: req.body.institution,
    bio: req.body.bio,
    major: req.body.major,
    mergedTo: userId,
    picture: pictureValue,
    skillone: req.body.skillone,
    skilltwo: req.body.skilltwo,
    skillthree: req.body.skillthree
  };
}

现在是前端代码(react.js):

这是我在 React 应用程序中加载的表单:

UserProfile.js

const UserProfile = (serverUserData) => {
  const appState = useContext(GlobalContext);
  const { currentUser } = appState;
  const { email, picture, name } = currentUser;
  const [isVerified, setIsVerified] = useState(false);

  const checkVerificationData = () => {
    axios.get("/api/v1/profiles/profile").then((res) => {
      const { data } = res;   
      if (data.verifiedDT) {
        setIsVerified(data.verifiedDT);
      }
    });
  };

  useEffect(() => {
    checkVerificationData();
  }, [isVerified]);


    // Upload user avatar function
  const [imageSelected, setImageSelected] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append('email', email);
    formData.append('name', name);
    formData.append('profileImg', imageSelected);

    axios
      .post(`/upload`, formData)
      .then(() => console.log("success"))
      .catch(err => console.log(err));
  };

  const onFileChange = (e) => {
    setImageSelected({ profileImg: e.target.files[0] });
  };
    };

 const classes = useStyles();
  return (
    <div className={classes.root}>
      <Grid item xs={12}
        container
        direction="row"
        justify="center"
        alignItems="center"
        spacing={4}>
        <Grid item>
          <Grid item>
            <UserCard
              picture={currentUser.picture}
              userEmail={email}
              name={name}
              isVerified={isVerified}
              handleSubmit={handleSubmit}
              onFileChange={onFileChange}
            />
            <br />
          </Grid>
        

这里是用户可以上传他们的个人资料照片的地方: UserCard.js

  {picture ? (
    <div>
      <Avatar
        src={picture}
        alt="Avatar"
        className="avatar--profile_image"
      />  
      <input
        type="file"
        onChange={onFileChange}
      />  
      <button onClick={handleSubmit}>Submit</button>
    </div>
  ) : (
    <AccountCircleIcon className="avatar--profile_image" />
  )}

因此,当输入内容并点击添加按钮时,我的 api 声明 req.file 未定义,我无法找出原因。

谁能帮我分析错误?

2 个答案:

答案 0 :(得分:1)

要上传文件,您需要使用 contentType: "multipart/form-data"。 参考以下实现文件上传。

helper 函数来创建一个带有所需标头的实例。您可以在此处添加任何其他人。

const getInstance = () => {
  return axios.create({
    headers: {
      "Content-Type": "multipart/form-data",
    },
  });
}

使用要上传的文件调用此方法

const fileUplaod = (file) => {

    let formData = new FormData();
    formData.append("images", file, file.name);
    
    getInstance()
      .post(endpoint_post_url, formData)
      .then((response) => {
        console.log("IMAGES_SUBMIT_SUCCESS");
      })
      .catch((err) => {
        console.error("image submit error", err);
      });
}

检查后端代码中的请求正文。您也可以将多张图片上传到同一媒体资源。它将是请求对象中的一个数组。

答案 1 :(得分:0)

编辑 handleSubmit 函数以向 axios 调用添加配置。

const handleSubmit = (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append('email', email);
    formData.append('name', name);
    formData.append('profileImg', imageSelected);

    axios
      .post(`/upload`, formData, {
         headers: {
           'Content-Type': "multipart/form-data"
         }
      })
      .then(() => console.log("success"))
      .catch(err => console.log(err));
  };
相关问题