反应:从节点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 服务器。
我在我的 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 服务器。