简体   繁体   English

文件上传错误 - 适用于 Postman 但不适用于前端

[英]File Upload Error - Works in Postman but not on frontend

I am working through the full stack certification on devchallenges.io and I'm doing the authentication app challenge .我正在通过 devchallenges.io 上的全栈认证,并且正在做身份验证应用程序挑战 So far I have been able to create the login and register functionality and have been able to set up the functionality to get the logged in user and display their information however, when trying to upload a file on the front end, the image upload doesn't seem to work.到目前为止,我已经能够创建登录和注册功能,并且能够设置功能以获取登录用户并显示他们的信息,但是,当尝试在前端上传文件时,图像上传不会t 似乎工作。 It works perfectly fine in Postman as shown in this video .如本视频所示,它在 Postman 中运行良好。 On the front end, other fields seem to get updated such as the name, bio.在前端,其他字段似乎得到了更新,例如姓名、简历。 Example of the error here . 这里的错误示例。

Github source code: https://github.com/gbopola/Auth-App Github 源代码: https://github.com/gbopola/Auth-App

server.js服务器.js

const express = require('express');
const connectDB = require('./config/db');
const app = express();
const { check, validationResult } = require('express-validator');
const User = require('./models/User');
const gravatar = require('gravatar');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('config');
const auth = require('./middleware/auth');
const cloudinary = require('./utils/cloudinary');
const upload = require('./utils/multer');

// Connect database
connectDB();

// Init Middleware
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ limit: '50mb', extended: true }));

// @route    POST /register
// @desc     Register user
// @access   Public
app.post(
  '/register',
  [
    check('email', 'Please include a valid email').isEmail(),
    check('password', 'Please enter a password').notEmpty(),
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    const { email, password } = req.body;

    try {
      // See if user exists
      let user = await AuthUser.findOne({ email });

      if (user) {
        return res
          .status(400)
          .json({ errors: [{ msg: 'User already exists' }] });
      }
      // Get users gravatar
      const avatar = gravatar.url(email, {
        s: '200',
        r: 'pg',
        d: 'mm',
      });

      user = new AuthUser({
        email,
        avatar,
        password,
      });

      // Encrypt password
      const salt = await bcrypt.genSalt(10);

      user.password = await bcrypt.hash(password, salt);

      await user.save();

      // Return jsonwebtoken
      const payload = {
        user: {
          id: user.id,
        },
      };

      jwt.sign(
        payload,
        config.get('jwtSecret'),
        { expiresIn: '5 days' },
        (err, token) => {
          if (err) throw err;
          res.json({ token });
        }
      );
    } catch (error) {
      console.error(error.message);
      res.status(500).send('Server error');
    }
  }
);

// @route    POST /login
// @desc     Authenticate user & get token
// @access   Public

app.post(
  '/login',
  check('email', 'Please include a valid email').isEmail(),
  check('password', 'Password is required').exists(),
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({
        errors: errors.array(),
      });
    }

    const { email, password } = req.body;

    try {
      // See if user exists
      let user = await User.findOne({ email });

      if (!user) {
        return res
          .status(400)
          .json({ errors: [{ msg: 'Invalid credentials' }] });
      }

      const isMatch = await bcrypt.compare(password, user.password);

      if (!isMatch) {
        return res
          .status(400)
          .json({ errors: [{ msg: 'Invalid credentials' }] });
      }

      // Return jsonwebtoken
      const payload = {
        user: {
          id: user.id,
        },
      };

      jwt.sign(
        payload,
        config.get('jwtSecret'),
        { expiresIn: '5 days' },
        (err, token) => {
          if (err) throw err;
          res.json({ token });
        }
      );
    } catch (err) {
      console.error(err.message);
      res.status(500).send('Server error');
    }
  }
);

// @route    GET /profile
// @desc     Get full user profile
// @access   Private

app.get('/profile', auth, async (req, res) => {
  try {
    let user = await User.findById(req.user.id).select('-password');

    res.json(user);
  } catch (err) {
    console.error(err.message);
    res.status(500).send('Server error');
  }
});

// @route    POST /profile/edit/:id
// @desc     edit profile
// @access   Private

app.put('/profile/edit/:id', upload.single('image'), auth, async (req, res) => {
  const { name, bio, email, phone, password } = req.body;

  try {
    let user = await AuthUser.findById(req.params.id);

    // Delete image from cloudinary
    if (user.cloudinary_id !== '')
      await cloudinary.uploader.destroy(user.cloudinary_id);

    // Upload image to cloudinary
    let result;
    if (req.file) {
      result = await cloudinary.uploader.upload(req.file.path);
    }

    const data = {
      name: name || user.name,
      avatar: (result && result.secure_url) || user.avatar,
      bio: bio || user.bio,
      email: email || user.email,
      phone: phone || user.phone,
      password: password || user.password,
      cloudinary_id: (result && result.public_id) || user.cloudinary_id,
    };

    if (password !== '') {
      // Encrypt password
      const salt = await bcrypt.genSalt(10);

      data.password = await bcrypt.hash(password, salt);
    }

    //   Update
    user = await User.findByIdAndUpdate(req.params.id, data, { new: true });

    return res.json(data);
  } catch (err) {
    console.error(err.message);
    res.status(500).send('Server error');
  }
});

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => console.log(`Server started on port ${PORT}`));

Auth Action.js验证 Action.js

// Update use profile
export const updateProfile = ({
  name,
  bio,
  phone,
  email,
  password,
  id,
  profileImg,
  navigate,
}) => {
  return async (dispatch) => {
    const config = {
      headers: {
        'Content-Type': 'application/json',
      },
    };
    const body = JSON.stringify({
      name,
      bio,
      phone,
      email,
      password,
      id,
      profileImg,
    });

    try {
      const res = await axios.put(`/profile/edit/${id}`, body, config);

      dispatch({
        type: PROFILE_UPDATE_SUCCESS,
        payload: res.data,
      });

      navigate('/profile');
    } catch (error) {
      console.log(error);
    }
  };
};

import React, { useEffect, useState, useRef } from 'react';
import { Navbar } from './Navbar';
import { useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';
import { loadUser } from '../redux/actions/auth';
import { Link, useParams, useNavigate } from 'react-router-dom';
import { store } from '../store';
import { updateProfile } from '../redux/actions/auth';
export const EditProfile = () => {
  const state = useSelector((state) => state.auth);
  const { id } = useParams();
  const dispatch = useDispatch();
  const navigate = useNavigate();
  // States
  const [isEditing, setEdit] = useState(false);
  const [profileImg, setImg] = useState(state.user.avatar);
  const [formData, setFormData] = useState({
    name: '',
    bio: '',
    phone: '',
    email: '',
    password: '',
  });

  const { email, password, bio, phone, name } = formData;

  const inputFile = useRef(null);

  let styles = {
    width: '72px',
    height: '72px',
    borderRadius: '8px',
    backgroundImage: `url(${!isEditing ? state.user.avatar : profileImg})`,
    backgroundPosition: 'center',
    backgroundSize: 'cover',
    position: 'relative',
  };

  // handle image change
  const imageHandler = (e) => {
    const reader = new FileReader();
    reader.onload = () => {
      if (reader.readyState === 2) {
        setImg(reader.result);
        setEdit(true);
      }
    };
    if (e.target.files[0]) {
      reader.readAsDataURL(e.target.files[0]);
    }
  };

  const changePhoto = () => {
    inputFile.current.click();
  };

  const onChange = (e) => {
    setFormData({ ...formData, [e.target.name]: e.target.value });
  };

  const changeInfo = () => {
    dispatch(
      updateProfile({
        name,
        bio,
        phone,
        email,
        password,
        id,
        profileImg,
        navigate,
      })
    );
  };

  return (
    <div className="EditProfile">
      <Navbar />
      <div className="edit-profile-container">
        <div className="back-to-profile">
          <Link className="link-to-profile" to="/profile">
            <span>
              <i className="fas fa-chevron-left"></i>
            </span>
            Back
          </Link>
        </div>
        <div className="profile-wrapper">
          <div className="profile-heading">
            <div>
              <h2>Change Info</h2>
              <p className="personal-info-grey">
                Changes will be reflected to every services
              </p>
            </div>
          </div>
          <div className="profile-photo">
            <input
              type="file"
              accept="image/*"
              name="image-upload"
              id="upload"
              onChange={imageHandler}
              ref={inputFile}
            />
            <div className="example" onClick={changePhoto}>
              <i className="fas fa-camera"></i>
              <div id="overlay"></div>
              <div id="profile-img-edit" style={styles}></div>
            </div>
            <p className="personal-info-grey change-photo">CHANGE PHOTO</p>
          </div>
          <div className="name">
            <label>Name</label>
            <input
              type="text"
              className="edit-profile-input"
              placeholder="Enter your name"
              name="name"
              value={name}
              onChange={(e) => onChange(e)}
            />
          </div>
          <div className="bio">
            <label>Bio</label>
            <textarea
              className="edit-profile-input"
              id="bio"
              placeholder="Enter your bio"
              name="bio"
              value={bio}
              onChange={(e) => onChange(e)}
            />
          </div>
          <div className="phone">
            <label>Phone</label>
            <input
              type="text"
              className="edit-profile-input"
              placeholder="Enter your phone"
              name="phone"
              value={phone}
              onChange={(e) => onChange(e)}
            />
          </div>
          <div className="email">
            <label>Email</label>
            <input
              type="text"
              className="edit-profile-input"
              placeholder="Enter your email"
              name="email"
              value={email}
              onChange={(e) => onChange(e)}
            />
          </div>
          <div className="password">
            <label>Password</label>
            <input
              type="password"
              className="edit-profile-input"
              placeholder="Enter your password"
              name="password"
              value={password}
              onChange={(e) => onChange(e)}
            />
            <button className="edit-save" onClick={changeInfo}>
              Save
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};

Usually you don't send the image to the user, you just send the url that leads to the image.通常您不会将图像发送给用户,您只需发送导致图像的url。

Normally passing images to the backend does not work unless you append it to a new form data -------------Example----------------- const formData = new FormData() formData.append('image', image)通常将图像传递到后端不起作用,除非您将其 append 传递给新的表单数据 -------------示例----- const formData = new FormData() formData.append('image', image)

then send formData as an object然后将 formData 作为 object 发送

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 API 在 postman 中工作正常,但在反应的前端部分中却没有 - API works fine in postman but not in frontend part of react 在 postman 中上传文件有效,但在 axios 中会引发 500 错误 - uploading file in postman works but in axios it throws 500 error .NET Core Web API中的IFormFile对于axios和ajax文件上载为空,但在Postman中有效 - IFormFile in .NET Core Web API is null for axios and ajax file upload but works in Postman 邮递员 - 带有文件上传的 POST 请求 - Postman - POST request with file upload 使用多个键上传POSTMAN文件 - POSTMAN file upload with multiple keys File Upload API与Postman一起使用,但与AngularJS不一起使用 - File Upload API working with Postman but not with AngularJS 在 POSTMAN 上使用 PUT/POST 方法上传文件 - Upload a file with PUT/POST method on POSTMAN 如何在本地主机上上传php文件并从前端站点访问它? - How to upload php file on local host and access it from frontend site? 无法在前端使用 Fetch API 将文件上传到 FastAPI 后端 - Cannot Upload File to FastAPI backend using Fetch API in the frontend 从移动设备/邮递员上传回送组件存储文件 - Loopback component storage file upload from mobile devices/postman
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM