【问题标题】:React: Image uploaded from node js backend is not rendering反应:从节点 js 后端上传的图像未呈现
【发布时间】:2021-05-27 16:00:45
【问题描述】:

我在我的 Node Js 后端使用 multer 从我的 React 前端上传文件。我一直将文件存储在 React 公共文件夹中。我一直在我的 MonogoDB 数据库中保存图像路径。这个想法是使用图像路径将图像插入我的 React 前端。帐户页面向后端发出 GET 请求以检索路径,但是我无法显示要显示的图像。使用开发工具“http://localhost:3000/user/account/frontend/public/uploads/1621968408663.jpg”检查时的路径。从 GET 请求发送的路径是 '../frontend/public/uploads/1621968408663.jpg'。我这样做对吗?有什么解决办法。

AccountPage.js

import React, {useEffect, useState} from "react";
import { Link, useParams } from "react-router-dom";
import Header from "./Header";
import axios from "axios";

import SettingsIcon from "@material-ui/icons/Settings";
import IconButton from "@material-ui/core/IconButton";

export default function AccountPage() {
    // Declare a new state variable, which we'll call "count"


    const { id } = useParams();

    const api = `http://localhost:5000/user/account/${id}`;

    const [ firstName, setFirstName ] = useState("");
    const [ lastName, setLastName ] = useState("");
    const [ emailAddress, setEmailAddress ] = useState("");
    const [ gender, setGender ] = useState("");
    const [ sexualPreference, setSexualPreference ] = useState("");
    const [ age, setAge ] = useState("");
    const [ description, setDescription ] = useState("");
    const [ matches, setMatches ] = useState([{}]);
    const [file, setFiles] = useState("")

    useEffect(() => {
      axios.get(api, {
        headers: {
          Authorization: localStorage.getItem("jwt"),
          "Content-Type": "application/json",
          "Cache-Control": "no-cache",
        },
      })
      .then((res) => {
        setFirstName(res.data.user.firstName)
        setLastName(res.data.user.lastName)
        setEmailAddress(res.data.user.emailAddress)
        setGender(res.data.user.gender)
        setSexualPreference(res.data.user.sexualPreference)
        setAge(res.data.user.age)
        setDescription(res.data.user.description)
        setMatches(res.data.user.matches)
        setFiles(res.data.user.path)
      });
    }, []);
        
    console.log(file)

    return (
      <div>
        <Header />
        <div>
        <img src={file}/>
        <p>{firstName} {lastName}</p>
        <p>{emailAddress}</p>
        <p>{gender}</p>
        <p>{sexualPreference}</p>
        <p>{age}</p>
        <p>{description}</p>
      </div>
      <Link to={`/user/settings/${id}`}><IconButton><SettingsIcon className="Header-icon" fontSize="large"/></IconButton></Link>
      </div>
    );
  }

app.js

require("dotenv").config();
const express = require('express');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const path = require('path'); 

const enableGlobalErrorLogging = process.env.ENABLE_GLOBAL_ERROR_LOGGING === 'true';

const app = express();

const corsOptions ={
  origin:'http://localhost:3000', 
  credentials:true,            //access-control-allow-credentials:true
  optionSuccessStatus:200
}

app.use(cors(corsOptions));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));

app.use(cookieParser());

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

const mongoose = require('mongoose');
const connection =  "password";

mongoose.connect(connection, {
    useNewUrlParser: true,
    useCreateIndex: true,
    useUnifiedTopology: true,
    useFindAndModify: false
});

const userRoutes = require('./routes/userRoutes');

app.use('/', userRoutes);

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Authorization, Content-Type, Accept");
  next();
});

// setup a friendly greeting for the root route
app.get('/', (req, res) => {
  res.json({
    message: 'Welcome to the REST API for Tinder!',
  });
 
});

// send 404 if no other route matched
app.use((req, res) => {
  res.status(404).json({
    message: 'Route Not Found',
  });
});

// setup a global error handler
app.use((err, req, res, next) => {
  if (enableGlobalErrorLogging) {
    console.error(`Global error handler: ${JSON.stringify(err.stack)}`);
  }

  res.status(err.status || 500).json({
    message: err.message,
    error: {},
  });
});

app.listen(5000, () => console.log('Listening on port 5000!'))

userRoutes.js

require("dotenv").config();

const express = require("express");
const router = express.Router({ mergeParams: true });
const jwt = require("jsonwebtoken");
const bcryptjs = require("bcryptjs");
const cookieParser = require('cookie-parser'); 
const { check, validationResult } = require("express-validator");

const multer = require('multer');

const User = require("../models/userSchema");

const ObjectID = require('mongodb').ObjectID;

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/')
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + '.jpg')
  }
})

const upload = multer({ storage: storage }) 

function asyncHandler(callback) {
  return async (req, res, next) => {
    try {
      await callback(req, res, next);
    } catch (error) {
      next(error);
      console.log(error);
    }
  };
}

router.post( "/user/create-account", upload.single("file"), [
    check("firstName")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "firstName"'),
    check("lastName")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "username"'),
    check("emailAddress")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "emailAddress"'),
    check("password")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "password"'),
    check("gender")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "gender"'),
    check("sexualPreference")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "sexualPreference"'),
    check("age")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "age"'),
    check("description")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "description"'),
  ],
  asyncHandler(async (req, res, next) => {
    // Attempt to get the validation result from the Request object.
    const errors = validationResult(req);

    // If there are validation errors...
    if (!errors.isEmpty()) {
      // Use the Array `map()` method to get a list of error messages.
      const errorMessages = errors.array().map((error) => error.msg);

      // Return the validation errors to the client.
      return res.status(400).json({ errors: errorMessages });
    }

    const {file, body: { firstName, lastName, emailAddress, password, gender, sexualPreference, age, description}} = req;

    console.log(firstName, lastName, emailAddress, password, gender, sexualPreference, age, description, file);
    
    //new user request body using mongo model from schema
    const postUser = new User({
      firstName: firstName,
      lastName: lastName,
      emailAddress: emailAddress,
      password: password,
      gender: gender,
      sexualPreference: sexualPreference,
      age: age,
      description: description,
      file: file,
      path: req.file.path
    });

    const userEmail = await User.findOne({
      emailAddress: postUser.emailAddress,
    });

    if (postUser.emailAddress === userEmail) {
      console.log("User with this email already exists");

      return res.status(500).end();

    } else if (postUser) {
      //if true salts the password with bcryptjs
      let salt = await bcryptjs.genSalt(10);
      const hashPass = await bcryptjs.hash(postUser.password, salt);
      postUser.password = hashPass;
      postUser.save();

      res.json({ postUser });

      return res.status(201).end();
    } else {
      res.status(400).send({ error: "Error: Account not created" }).end();
    }
  })
);

【问题讨论】:

    标签: node.js reactjs image multer src


    【解决方案1】:

    图像 url 需要指向后端提供图像的位置。当您导航到 http://localhost:3000/user/account/frontend/public/uploads/1621968408663.jpg 时,您可能看不到该图像,因为该位置不存在该图像。

    首先,localhost:3000 是您的前端,因此您需要将其更改为指向您的后端:localhost:5000

    其次,您在 /uploads 路由上提供上传文件夹,因此该文件夹内的所有内容都将在 http://localhost:5000/uploads/... 上可用。因此,如果您导航到 http://localhost:5000/uploads/1621968408663.jpg,您应该会看到该图像。

    所以我们需要从:

    http://localhost:3000/user/account/frontend/public/uploads/1621968408663.jpg

    到:

    http://localhost:5000/uploads/1621968408663.jpg.

    当您将用户保存在userRoutes.js 中时,您将User.path 设置为req.file.path,最终成为uploads/1621968408663.jpg。到目前为止一切顺利。

    AccountPage.js 中,您使用&lt;img src={file}/&gt; 设置图像源,它本质上是&lt;img src="uploads/1621968408663.jpg"/&gt;。这就是事情出错的地方。由于这是一个相对 url,字符串被附加到当前页面的 URL 上。

    要解决此问题,请将图像源更改为:

    <img src={`http://localhost:5000/${file}`} />
    

    【讨论】:

    • 我已经用我的后端文件更新了帖子上的代码。谢谢你顺便说一句!我将文件存储在一个名为 uploads 的文件夹中。干杯!
    • 用户模型的 MongoDB 中path 的值是多少? uploads 文件夹(存储图像的位置)是否与 app.js 位于同一文件夹中?在浏览器中检查时,img 元素的 src 值是多少?
    • path的值是设置图片存放的url路径。例如:uploads/elephant.jpeg。它以字符串形式存储在 MongoDB 模式中。在浏览器中检查时,路径会添加http://localhost:3000/user/account。我曾尝试使用http://${files} 将其删除,但它也不起作用。例如,检查时的完整路径是http://localhost:3000/user/account/uploads/1622056746800.jpg
    • 我明白了。存储在 MongoDB 中的路径字符串看起来不错。如果你去http://localhost:3000/uploads/1622056746800.jpg,你看到图片了吗?如果是这样,那么我们需要摆脱/user/account/img 元素是否与AccountPage.js 中的相同,这一行:&lt;img src={file}/&gt;?这是原生元素还是从其他地方导入的自定义元素?
    • 查看了存储库并更新了我的答案。让我知道它是否解决了您的问题,祈祷??
    【解决方案2】:

    您需要创建一个静态文件夹来提供图像。 如果您使用过 express.js,请尝试 this。你也可以试试this 做一个简单的nodejs服务器。

    【讨论】:

    • 我使用了 express,不幸的是 app.use(express.static('uploads')) 不起作用,谢谢您
    猜你喜欢
    • 2019-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 1970-01-01
    • 1970-01-01
    • 2018-04-25
    • 2020-04-21
    相关资源
    最近更新 更多