反应:从节点js后端上传的图像未呈现

React: Image uploaded from node js backend is not rendering

我在我的 Node Js 后端使用 multer 从我的 React 前端上传文件。我一直将文件存储在 React public 文件夹中。我一直在我的 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();
    }
  })
);

图像 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 中,您将图像源设置为 <img src={file}/>,本质上是 <img src="uploads/1621968408663.jpg"/>。这就是问题所在。由于这是一个相对的 url,该字符串将附加到当前页面的 URL。

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

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

您需要创建一个静态文件夹来提供图像。 如果您使用过 express.js 然后尝试 this. You can also try this 一个简单的 nodejs 服务器。