TypeError: Cannot read property 'filename' of undefined 'getting this error while creating a User'
TypeError: Cannot read property 'filename' of undefined 'getting this error while creating a User'
我正在尝试创建一个带有头像的用户。我正在使用 multer,我不知道如何使用 multer 我只是按照文档操作,但是当我尝试使用个人资料图片创建用户时它显示错误 TypeError: Cannot read property 'filename' of undefined
。我正在使用 MongoDB、express.js 作为后端。
这是我的代码
型号(user.js)
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const userSchema = new mongoose.Schema({
firstName: {
type: String,
required: true,
trim: true,
min: 3,
max: 20
},
lastName: {
type: String,
required: true,
trim: true,
min: 3,
max: 20
},
username: {
type: String,
required: true,
trim: true,
unique: true,
index: true,
lowercase: true
},
email: {
type: String,
required: true,
trim: true,
unique: true,
lowercase: true
},
hash_password: {
type: String,
required: true
},
profilePicture: { type: String }
}, { timestamps: true });
userSchema.virtual('fullName').get(function () {
return `${this.firstName} ${this.lastName}`
});
userSchema.methods = {
authenticate: async function (password) {
return await bcrypt.compare(password, this.hash_password);
}
};
module.exports = mongoose.model('User', userSchema);
控制器(auth.js)
const User = require('../models/user');
const bcrypt = require('bcrypt');
const shortid = require('shortid');
exports.signup = async (req, res) => {
User.findOne({ email: req.body.email }).exec(async (error, user) => {
if (error) return res.status(400).json({ error })
if (user)
return res.status(400).json({
message: "User already registered",
});
const { firstName, lastName, email, password } = req.body;
const hash_password = await bcrypt.hash(password, 10);
const profilePicture = req.file.filename
const userSignUp = {
firstName,
lastName,
email,
hash_password,
profilePicture: profilePicture,
username: shortid.generate(),
}
const _user = new User(userSignUp);
_user.save((error, data) => {
if (error) {
return res.status(400).json({
message: error,
});
}
if (data) {
return res.status(201).json({
message: "user created Successfully..!",
});
}
});
});
};
路由器(auth.js)
const express = require('express');
const { signup, signin, signout } = require('../controller/auth');
const { validateSignupRequest, isRequestValidated, validateSigninRequest } = require('../../validators/auth');
const router = express.Router();
const path = require('path');
const multer = require('multer');
router.use(express.static(__dirname+ '../../uploads'));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, '../../uploads')
},
filename: (req,file, cb) => {
cb(null, file.filename + "_" + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({ storage: storage }).single('profilePicture');
router.post('/signup', validateSignupRequest,isRequestValidated,upload,signup);
module.exports = router
index.server.js
const express = require('express');
const mongoose = require('mongoose');
const env = require('dotenv');
const cors = require('cors');
const app = express();
env.config();
// connecting to mongoose database
mongoose.connect(process.env.DATABASE,
{
useNewUrlParser:true,
useUnifiedTopology:true,
useCreateIndex: true,
useFindAndModify: false
}).then(() => {
console.log('database connected successfully')
}).catch((err) => {
console.log(err)
});
// routes
const authRoutes = require('./Home_Search_Client/routes/auth');
// middlewares
app.use(cors());
app.use(express.json());
app.use('/api', authRoutes);
// PORT NUMBER
app.listen(process.env.PORT, () => {
console.log(`server is running at port: ${process.env.PORT}`)
});
前端 (React、Redux)
动作(user.action.js)
import axios from '../helpers/axios';
import { userContants } from './constants';
export const signup = (user) => {
console.log(user)
return async (dispatch) => {
dispatch({ type: userContants.USER_REGISTER_REQUEST });
const res = await axios.post(`/signup`, {
...user
});
if (res.status === 201) {
const { message } = res.data;
dispatch({
type: userContants.USER_REGISTER_SUCCESS,
payload: { message }
});
} else {
if (res.status === 400) {
dispatch({
type: userContants.USER_REGISTER_FAILURE,
payload: { error: res.data.error }
});
}
}
}
};
减速机(user.reducer.js)
import { userContants } from "../actions/constants"
const initState = {
error: null,
message: '',
loading: false
}
export default (state = initState, action) => {
switch (action.type) {
case userContants.USER_REGISTER_REQUEST:
state = {
...state,
loading: true
}
break;
case userContants.USER_REGISTER_SUCCESS:
state = {
...state,
loading: false,
message: action.payload.message
}
break;
case userContants.USER_REGISTER_FAILURE:
state = {
...state,
loading: false,
error: action.payload.error
}
break;
}
return state;
}
容器(Signup.js)
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Button, Col, Container, Form, Row } from 'react-bootstrap'
import Layout from '../../Components/Layout'
import Input from '../../Components/UI/Input'
import { signup } from '../../actions'
import { Redirect } from 'react-router-dom';
const Signup = (props) => {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [profilePicture, setProfilePicture] = useState('');
const auth = useSelector((state) => state.auth)
const user = useSelector((state) => state.user)
const dispatch = useDispatch();
useEffect(() => {
if(!user.loading){
setFirstName('');
setLastName('');
setEmail('');
setPassword('');
setProfilePicture('')
}
}, [user.loading]);
const userSignup = (e) => {
e.preventDefault();
const user = {
firstName,
lastName,
email,
password,
profilePicture
};
dispatch(signup(user));
console.log(user)
};
if(auth.authenticate) {
return <Redirect to={'/'} />
}
if(user.loading) {
return <p>Loading...</p>
}
const handleProfilePicture = (e) => {
setProfilePicture(e.target.files[0]);
}
return (
<Layout>
<Container>
{user.message}
<Row>
<Col md={{ span:6, offset:3 }}>
<Form onSubmit={userSignup}>
<Row>
<Col md = {6}>
<Input
label = 'First Name'
placeholder='First Name'
value= {firstName}
type='text'
onChange={(e) => setFirstName(e.target.value)}
/>
</Col>
<Col md = {6}>
<Input
label = 'Last Name'
placeholder='Last Name'
value= {lastName}
type='text'
onChange={(e) => setLastName(e.target.value)}
/>
</Col>
</Row>
<Input
label='Email'
placeholder='Email'
value={email}
type='email'
onChange={(e) => setEmail(e.target.value)}
/>
<Input
label='Password'
placeholder='Password'
value={password}
type='password'
onChange={(e) => setPassword(e.target.value)}
/>
<input type="file" name= 'profilePicture' onChange={handleProfilePicture} />
<Button variant='primary' type='submit' >
Submit
</Button>
</Form>
</Col>
</Row>
</Container>
</Layout>
)
}
export default Signup
要从前端发送文件和其他数据,您需要使用 FormData API。使用 user
对象和 axios,我会做这样的事情:
const formData = new FormData();
// Append all properties of the `user` object to the form
for (const [key, value] of Object.entries(user)) {
formData.append(key, value);
}
const response = await axios.post('/signup', formData, {
headers: {
// Multer only parses "multipart/form-data" requests
'Content-Type': 'multipart/form-data',
},
});
我正在尝试创建一个带有头像的用户。我正在使用 multer,我不知道如何使用 multer 我只是按照文档操作,但是当我尝试使用个人资料图片创建用户时它显示错误 TypeError: Cannot read property 'filename' of undefined
。我正在使用 MongoDB、express.js 作为后端。
这是我的代码
型号(user.js)
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const userSchema = new mongoose.Schema({
firstName: {
type: String,
required: true,
trim: true,
min: 3,
max: 20
},
lastName: {
type: String,
required: true,
trim: true,
min: 3,
max: 20
},
username: {
type: String,
required: true,
trim: true,
unique: true,
index: true,
lowercase: true
},
email: {
type: String,
required: true,
trim: true,
unique: true,
lowercase: true
},
hash_password: {
type: String,
required: true
},
profilePicture: { type: String }
}, { timestamps: true });
userSchema.virtual('fullName').get(function () {
return `${this.firstName} ${this.lastName}`
});
userSchema.methods = {
authenticate: async function (password) {
return await bcrypt.compare(password, this.hash_password);
}
};
module.exports = mongoose.model('User', userSchema);
控制器(auth.js)
const User = require('../models/user');
const bcrypt = require('bcrypt');
const shortid = require('shortid');
exports.signup = async (req, res) => {
User.findOne({ email: req.body.email }).exec(async (error, user) => {
if (error) return res.status(400).json({ error })
if (user)
return res.status(400).json({
message: "User already registered",
});
const { firstName, lastName, email, password } = req.body;
const hash_password = await bcrypt.hash(password, 10);
const profilePicture = req.file.filename
const userSignUp = {
firstName,
lastName,
email,
hash_password,
profilePicture: profilePicture,
username: shortid.generate(),
}
const _user = new User(userSignUp);
_user.save((error, data) => {
if (error) {
return res.status(400).json({
message: error,
});
}
if (data) {
return res.status(201).json({
message: "user created Successfully..!",
});
}
});
});
};
路由器(auth.js)
const express = require('express');
const { signup, signin, signout } = require('../controller/auth');
const { validateSignupRequest, isRequestValidated, validateSigninRequest } = require('../../validators/auth');
const router = express.Router();
const path = require('path');
const multer = require('multer');
router.use(express.static(__dirname+ '../../uploads'));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, '../../uploads')
},
filename: (req,file, cb) => {
cb(null, file.filename + "_" + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({ storage: storage }).single('profilePicture');
router.post('/signup', validateSignupRequest,isRequestValidated,upload,signup);
module.exports = router
index.server.js
const express = require('express');
const mongoose = require('mongoose');
const env = require('dotenv');
const cors = require('cors');
const app = express();
env.config();
// connecting to mongoose database
mongoose.connect(process.env.DATABASE,
{
useNewUrlParser:true,
useUnifiedTopology:true,
useCreateIndex: true,
useFindAndModify: false
}).then(() => {
console.log('database connected successfully')
}).catch((err) => {
console.log(err)
});
// routes
const authRoutes = require('./Home_Search_Client/routes/auth');
// middlewares
app.use(cors());
app.use(express.json());
app.use('/api', authRoutes);
// PORT NUMBER
app.listen(process.env.PORT, () => {
console.log(`server is running at port: ${process.env.PORT}`)
});
前端 (React、Redux)
动作(user.action.js)
import axios from '../helpers/axios';
import { userContants } from './constants';
export const signup = (user) => {
console.log(user)
return async (dispatch) => {
dispatch({ type: userContants.USER_REGISTER_REQUEST });
const res = await axios.post(`/signup`, {
...user
});
if (res.status === 201) {
const { message } = res.data;
dispatch({
type: userContants.USER_REGISTER_SUCCESS,
payload: { message }
});
} else {
if (res.status === 400) {
dispatch({
type: userContants.USER_REGISTER_FAILURE,
payload: { error: res.data.error }
});
}
}
}
};
减速机(user.reducer.js)
import { userContants } from "../actions/constants"
const initState = {
error: null,
message: '',
loading: false
}
export default (state = initState, action) => {
switch (action.type) {
case userContants.USER_REGISTER_REQUEST:
state = {
...state,
loading: true
}
break;
case userContants.USER_REGISTER_SUCCESS:
state = {
...state,
loading: false,
message: action.payload.message
}
break;
case userContants.USER_REGISTER_FAILURE:
state = {
...state,
loading: false,
error: action.payload.error
}
break;
}
return state;
}
容器(Signup.js)
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Button, Col, Container, Form, Row } from 'react-bootstrap'
import Layout from '../../Components/Layout'
import Input from '../../Components/UI/Input'
import { signup } from '../../actions'
import { Redirect } from 'react-router-dom';
const Signup = (props) => {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [profilePicture, setProfilePicture] = useState('');
const auth = useSelector((state) => state.auth)
const user = useSelector((state) => state.user)
const dispatch = useDispatch();
useEffect(() => {
if(!user.loading){
setFirstName('');
setLastName('');
setEmail('');
setPassword('');
setProfilePicture('')
}
}, [user.loading]);
const userSignup = (e) => {
e.preventDefault();
const user = {
firstName,
lastName,
email,
password,
profilePicture
};
dispatch(signup(user));
console.log(user)
};
if(auth.authenticate) {
return <Redirect to={'/'} />
}
if(user.loading) {
return <p>Loading...</p>
}
const handleProfilePicture = (e) => {
setProfilePicture(e.target.files[0]);
}
return (
<Layout>
<Container>
{user.message}
<Row>
<Col md={{ span:6, offset:3 }}>
<Form onSubmit={userSignup}>
<Row>
<Col md = {6}>
<Input
label = 'First Name'
placeholder='First Name'
value= {firstName}
type='text'
onChange={(e) => setFirstName(e.target.value)}
/>
</Col>
<Col md = {6}>
<Input
label = 'Last Name'
placeholder='Last Name'
value= {lastName}
type='text'
onChange={(e) => setLastName(e.target.value)}
/>
</Col>
</Row>
<Input
label='Email'
placeholder='Email'
value={email}
type='email'
onChange={(e) => setEmail(e.target.value)}
/>
<Input
label='Password'
placeholder='Password'
value={password}
type='password'
onChange={(e) => setPassword(e.target.value)}
/>
<input type="file" name= 'profilePicture' onChange={handleProfilePicture} />
<Button variant='primary' type='submit' >
Submit
</Button>
</Form>
</Col>
</Row>
</Container>
</Layout>
)
}
export default Signup
要从前端发送文件和其他数据,您需要使用 FormData API。使用 user
对象和 axios,我会做这样的事情:
const formData = new FormData();
// Append all properties of the `user` object to the form
for (const [key, value] of Object.entries(user)) {
formData.append(key, value);
}
const response = await axios.post('/signup', formData, {
headers: {
// Multer only parses "multipart/form-data" requests
'Content-Type': 'multipart/form-data',
},
});