Node & React, изображение не отображается, а наоборот - PullRequest
0 голосов
/ 23 января 2020

Итак, после того, как я сделаю POST-запрос для загрузки изображения для пользователя, изображение не отображается, а alt, я не знаю, что вызывает это, так как я не получаю никакой ошибки, и кажется, что работать, только то, что отображает alt изображения, но не само изображение. Вот некоторые из моих кодов, а также ссылка на репозиторий github.

https://github.com/tigerabrodi/ELance

Действие пользователя

  export const updateUserImage = (image) => async dispatch => {
    const formData = new FormData();
    formData.append("image", image)
    const config = {
      headers: {
        "Content-Type": "multipart/form-data"
      }
    }

    try {
      const res = await axios.post("/api/users/avatar", formData, config);


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

      dispatch(loadUser());
    } catch (err) {
      const errors = err.response.data.errors;

      if (errors) {
        errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
      }

      dispatch({
        type: UserActionTypes.USER_ERROR
      });
    }


  }

пользовательский редуктор

import {UserActionTypes} from "./user.types";


const initialState = {
    token: localStorage.getItem("token"),
    isAuthenticated: null,
    loading: true,
    user: null
}


const userReducer = (state = initialState, action) => {
    const {type, payload} = action;
    switch (type) {
        case UserActionTypes.USER_LOADED:
          case UserActionTypes.USER_IMAGE_UPDATED:
          return {
            ...state,
            isAuthenticated: true,
            loading: false,
            user: payload
          };
        case UserActionTypes.REGISTER_SUCCESS:
        case UserActionTypes.LOGIN_SUCCESS:
          localStorage.setItem('token', payload.token);
          return {
            ...state,
            ...payload,
            isAuthenticated: true,
            loading: false
          };
        case UserActionTypes.REGISTER_FAIL:
        case UserActionTypes.AUTH_ERROR:
        case UserActionTypes.LOGIN_FAIL:
        case UserActionTypes.LOGOUT:
        case UserActionTypes.ACCOUNT_DELETED:
          case UserActionTypes.USER_ERROR:
          localStorage.removeItem('token');
          return {
            ...state,
            token: null,
            isAuthenticated: false,
            loading: false
          };
        default:
          return state;
    }
}

export default userReducer

Панель инструментов js (куда загружается изображение)

import React, {useEffect, Fragment, useState} from 'react';
import {connect} from "react-redux";
import {getCurrentProfile, deleteAccount} from "../../redux/profile/profile.actions";
import {Link} from "react-router-dom"
import Spinner from "../layout/Spinner";
import DashboardActions from "./DashboardActions"
import Experience from './Experience';
import Education from './Education';
import defaultUserImage from "../../assets/default-user-icon.jpg";
import {updateUserImage} from "../../redux/user/user.actions";

const Dashboard = ({
    deleteAccount,
    getCurrentProfile,
    updateUserImage,
    auth: {
        user
    },
    profile: {
        profile,
        loading
    }
}) => {
    useEffect(() => {
        getCurrentProfile();
    }, [getCurrentProfile]);

    const [file, setFile] = useState('');
    const [imageFile, setImageFile] = useState(false);

    const onChange = e => {
        setFile(e.target.files[0]);
        setImageFile(!imageFile);
      };

      const onSubmit = e => {
          e.preventDefault();
          updateUserImage(file);
      }

    return loading && profile === null
        ? <Spinner/>
        : <Fragment>
            <div className="container">
                <div className="row">
                    <div className="col text-center">
                        <h1 className="display-1 text-warning">Dashboard</h1>
                        <p className="lead text-info">
                            <i className="fas fa-user"/>
                            Welcome {user && user.name}
                        </p>
                        <div className="col sm-5">
                                                <img src={user.avatar ? user.avatar : defaultUserImage} alt="avatar" className="border border-success rounded-circle m-2" />
                        </div>
                        <form onSubmit={onSubmit}>
                        <div class="input-group mb-3">
                        <div class="input-group-prepend">
                          <span class="input-group-text">Image</span>
                        </div>
                        <div class="custom-file">
                          <input type="file" onChange={e => onChange(e)} class="custom-file-input bg-info" />
                          <label class="custom-file-label">Upload Image</label>
                        </div>
                      </div>
                      {imageFile && (
                                               <input type="submit" value="Submit Upload" className="btn btn-info btn-block m-2" /> 
                      )}

                        </form>
                    </div>
                </div>
            </div>

            {profile !== null
                ? (
                    <Fragment>
                        <DashboardActions/>
                        <Experience experience={profile.experience}/>
                        <Education education={profile.education}/>

                        <div className="container">
                            <div className="row">
                                <div className="col text-center">
                                    <div className="my-2">
                                        <button className="btn-danger" onClick={() => deleteAccount()}>
                                            <i className="fas fa-user-minus text-dark"/>
                                            Delete My Account
                                        </button>
                                    </div>
                                </div>
                            </div>

                        </div>

                    </Fragment>
                )
                : (
                    <Fragment>
                        <div className="container">
                            <div className="row">
                                <div className="col text-center">
                                    <p>You have not yet setup a profile, please add some info</p>
                                    <Link to='/create-profile' className='btn btn-info my-1'>
                                        Create Profile
                                    </Link>
                                </div>
                            </div>
                        </div>

                    </Fragment>
                )}
        </Fragment>
}

const mapStateToProps = state => ({auth: state.auth, profile: state.profile})

export default connect(mapStateToProps, {getCurrentProfile, deleteAccount, updateUserImage})(Dashboard);

серверный маршрут пользователя

// @route    POST api/users/avatar
// @desc     Update Users Avatar
// @access   Private
router.post("/avatar", auth, async (req, res) => {
  try {
    let user = await User.findById(req.user.id);

    if (!user) {
      return res.status(404).json({msg: "User was not found"})
    }

    if (!req.file) {
      return res.status(400).json({msg: "Please upload a file"});
    }

    const imageUrl = req.file.path.replace("\\" ,"/");;

     user = await User.findByIdAndUpdate(req.user.id, {avatar: imageUrl});
     await user.save();
    res.status(200).json(user);
  } catch (err) {
    console.error(err.message);
    return res.status(500).json({msg: "Server error"});
  }
})

сервер. js

const express = require('express');
const connectDB = require('./config/db');
const uuidv4 = require("uuid/v4")
const colors = require("colors");
const morgan = require("morgan");
const multer = require("multer");
const path = require("path");
const app = express();
const PORT = process.env.PORT || 9065;

// Connect Database
connectDB();

// Configuring Multer storage
const fileStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'images');
  },
  filename: (req, file, cb) => {
    cb(null, uuidv4() + "_" + file.originalname);
  }
});

const fileFilter = (req, file, cb) => {
  if (
    file.mimetype === 'image/png' ||
    file.mimetype === 'image/jpg' ||
    file.mimetype === 'image/jpeg'
  ) {
    cb(null, true);
  } else {
    cb(null, false);
  }
};


// Init Middleware
app.use(express.json({ extended: false }));

// Use Multer
app.use(
  multer({ storage: fileStorage, fileFilter: fileFilter }).single('image')
);

// Dev logging middleware
if (process.env.NODE_ENV === "development") {
  app.use(morgan("dev"));
}

// Define Routes
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
app.use('/api/posts', require('./routes/api/posts'));

// Serve static assets in production
if (process.env.NODE_ENV === 'production') {
  // Set static folder
  app.use(express.static('client/build'));

  app.get('*', (req, res) => {
    res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
  });
}



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

Ответы [ 2 ]

0 голосов
/ 23 января 2020

Я забыл на сервере папку с изображениями как stati c на сервере. js

app.use('/images', express.static(path.join(__dirname, 'images')));

0 голосов
/ 23 января 2020

Хранить изображение на стороне клиента:

const fileStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, './client/public/images/');
  },
  filename: (req, file, cb) => {
    cb(null, uuidv4() + "_" + file.originalname.replace(/\s/g, ''));
  }
});
...