我正在开发一个非常简单的社交媒体应用程序,用户可以在其中注册、登录、创建帖子、编辑他们的个人资料和帖子、删除帖子以及完全删除自己。
应适当地创建和使用通过 jwt 的令牌,并且用户将所有相关文件上传到 cloudinary。其中个人资料图片存储在 profile_pictures 文件夹中,帖子存储在 user_posts 文件夹中。
上周五测试时,所有这些都有效。然而现在,当我坐下来修复前端的令牌时,突然间我突然无法再注册用户了。所以我去了后端,检查了代码,去了 Postman,测试了路由,它没有填充请求正文。
现在还有更多的问题,例如,文件上传到 cloudinary 也不再起作用,我不知道这是否是由于最近的 API 更新所致,尽管他们的页面上写着“上次更新” 6 月 15 日”,我的最后一次注册和登录测试是在 6 月 16 日星期五,这让我认为如果它有效,那么它现在应该仍然有效。但事实并非如此。
不过,所有这些并不是我提出这个问题并寻求帮助的原因。我已禁用应用程序中所有与文件上传相关的代码,以测试 mongo db atlas 用户对象的创建。
这就是我的问题所在。由于某种超出我知识和理解范围的原因,Postman 不会通过表单数据填充任何内容,即使一切看起来都按顺序进行,内容类型是正确的,要创建的用户对象的字段是正确的。
如果我在 Postman 中使用原始输入,它只会填充它。我已经束手无策了......
如果有人知道这个问题,我将非常感谢您的帮助。
以下是相关代码,请忽略注释掉的文件相关代码行。
// AUTH CONTROLLER: // controller for user signup module.exports.signup = async (req, res, next) => { try { console.log(req.body, "req body"); // retrieve user from db by email provided in request body const foundUser = await User.findOne({ email: req.body.email }); console.log(foundUser, "found user"); // check if foundUser already exists in db if (foundUser) { res.status(409).json({ message: `Email already in use. Please choose another.` }); } // generate salt and hash for the user password const salt = bcrypt.genSaltSync(Number(process.env.SALT_ROUND)); const hash = bcrypt.hashSync(req.body.password, salt); // create a new user object from user model const newUser = new User({ username: req.body.username, name: req.body.name, email: req.body.email, password: hash, //profilePicture: req.file.path }); // console.log(req.file, "req file"); await newUser.save(); // save the new user object to the database // upload the profile picture to cloudinary storage // const result = await cloudinary.uploader.upload(req.file.path, { // public_id: `profile_pictures/${newUser._id}`, // }); //newUser.profilePicture = result.secure_url; //await newUser.save(); // update newUser with the profilePicture URL console.log(newUser, "new user"); // generate a signup token // const token = jwt.sign({ newUserId: newUser._id, newUserName: newUser.username, newUserProfilePicture: newUser.profilePicture }, process.env.JWT_SECRET, { // expiresIn: '5m' // expires in 5 minutes (in case signup was erroneous) // }); // store the token as a cookie // res.cookie('jwt', token, { // httpOnly: true // }); // respond with the newly created user object and the created token res.status(201).json({ message: `User created successfully!`, user: newUser }); } catch (err) { next(err); }; };
// AUTH ROUTE: // import dependencies const express = require('express') const authController = require('../controllers/authController') //const authHandler = require('../middlewares/authHandler') // create new router object const router = express.Router() // import controllers router.post('/signup', authController.signup) //router.post('/login', authController.login) //router.get('/logout', authHandler.checkUser, authController.logout) module.exports = router
// USER MODEL: const mongoose = require("mongoose") const bcrypt = require("bcrypt") const UserSchema = new mongoose.Schema({ email: { type: String, required: true, unique: true }, password: { type: String, required: true }, name: { type: String, required: true }, username: { type: String, unique: true }, //profilePicture: { type: String }, }) // usually you hash/salt inside the appropriate model; like our userModel here. // // but we save the user-object twice for following two reasons: // - the regular data of the user-object gets saved to our mongoDB atlas database. // - and the profile picture gets uploaded and saved in an appropriate folder to cloudinary. // // this triggers the password hash twice, which in return falsifies the user password on login attempt. // therefore we ignore the code snippet below and directly salt and hash in our authController. // // hash and salt user password before saving to database // UserSchema.pre("save", async function (next) { // const salt = await bcrypt.genSalt(); // this.password = await bcrypt.hash(this.password, salt); // next(); // }); // pre-hook for updating password field UserSchema.pre('findOneAndUpdate', function (next) { const update = this.getUpdate() if (update.password) { bcrypt.hash(update.password, Number(process.env.SALT_ROUND), function (err, hash) { if (err) return next(err) update.password = hash next() }) } }) // compare the password entered by the user with the hashed password in the database UserSchema.methods.comparePassword = function (candidatePassword, cb) { bcrypt.compare(candidatePassword, this.password, function (err, isMatch) { if (err) return cb(err) //cb(err) passes errors down to error handler the same way next(err) does cb(null, isMatch) }) } const User = mongoose.model("User", UserSchema) module.exports = User
// SERVER: // import dependencies const cors = require('cors'); const express = require('express'); const cookieParser = require('cookie-parser'); // import routes (modules) const authRoute = require('./routes/authRoute'); const userRoute = require('./routes/userRoute'); const postRoute = require('./routes/postRoute'); const app = express(); // initialize express // import middlewares const { connectMongoDB } = require('./lib/mongoose'); // destruct mongoDB connector const { errorHandler } = require('./middlewares/errorHandler'); // destruct errorHandler // allow requests from specified origins with specific methods const whitelist = [process.env.FRONTEND_URL, 'https://www.arii.me']; // add cors options const corsOptions = { origin: (origin, callback) => { if (whitelist.indexOf(origin) !== -1 || !origin) { callback(null, true); } else { callback(new Error('CORS issues')); }; }, credentials: true, }; // enable cross-origin resource sharing with specified options for the express app app.use(cors(corsOptions)); // parse incoming cookies and make them accessible in req.cookies app.use(cookieParser()); // enable parsing of incoming JSON data in the request body by the express app app.use(express.json()); app.use(express.urlencoded({ extended: false })); // define routes app.use('/auth', authRoute); app.use('/users', userRoute); app.use('/posts', postRoute); // define middlewares connectMongoDB(); app.use(errorHandler); // error handler must be last invoked middleware // listen to server app.listen(process.env.PORT || 3003, () => { console.log(`Server up and running at ${process.env.PORT}`); });
// MONGOOSE: // import dependencies const mongoose = require('mongoose'); require('dotenv').config(); // destruct envs const { DB_USER, DB_PASS, DB_HOST, DB_NAME } = process.env; // atlas connection string const mongoURI = `mongodb+srv://${DB_USER}:${DB_PASS}@${DB_HOST}/${DB_NAME}?retryWrites=true&w=majority`; // middleware function for handling connections to the mongoDB atlas database module.exports.connectMongoDB = async () =>{ try { await mongoose.connect(mongoURI, { useNewUrlParser: true, useUnifiedTopology: true, }); console.log(`Connected to MongoDB Atlas!`); } catch (err) { console.log(`Couldn't Connect to MongoDB Atlas!`); next(err); } }
抱歉,如果这太多了,但这是所有相关的代码,我失去了理智。 我知道公开 ENV 并不明智,但这只是我自己的一个练习,因此我毫无疑虑地分享 ENV。
我非常感谢有关此事的所有意见。
更新:
我已经修复了请求正文未填充以下代码的问题:
// In the auth route I imported multer: const multer = require('multer') const upload = multer() // Then I added a method to the auth route before signup is called: router.post('/signup', upload.none(), authController.signup) // I have also forfeited any file upload during signup // and replaced them with a default image in my cloudinary assets. // Here's the updated userModel profilePicture field: profilePicture: { type: String, default: 'res.cloudinary.com/ddb2abwuu/image/upload/v1687256495/…' }
通过执行这些步骤,它现在可以正确填充请求正文,我也可以使用 Postman 表单数据和在前端再次创建用户。
用户可以选择稍后通过修补程序上传自己的配置文件来更改默认的配置文件图片。其他网站以类似的方式处理用户获取。
不要问我为什么我必须突然做这些心理体操,虽然一切都像几天前一样有效,但我们已经到了。
我强烈怀疑我使用的至少一个包和依赖项有某种 API 更新,这完全把我搞砸了。
就目前情况而言,此票证现已解决。希望这对将来遇到同样奇怪问题的人有用。
P粉0215534602024-04-02 09:20:01
到目前为止,我找到了一个令我难以置信的解决方案:在我的 authRoute 中,我必须显式导入 multer 然后创建
const multer = require('multer') const upload = multer()
然后在身份验证路由中指定:
router.post('/signup', upload.none(), authController.signup)
我还放弃了注册过程中的任何文件上传,只是手动将默认的个人资料图片添加到我的 cloudinary 资产中,并将其添加到我的用户模型中:
profilePicture: { type: String, default: 'res.cloudinary.com/ddb2abwuu/image/upload/v1687256495/…' }
这样注册和登录就可以再次工作了。
通过执行这些步骤,它现在可以正确填充请求正文,我也可以使用 Postman 表单数据和在前端再次创建用户。
用户可以选择稍后通过修补程序上传自己的配置文件来更改默认的配置文件图片。其他网站以类似的方式处理用户获取。
不要问我为什么我必须突然做这些心理体操,虽然一切都像几天前一样有效,但我们已经到了。
我强烈怀疑我使用的至少一个包和依赖项有某种 API 更新,这完全把我搞砸了。
就目前情况而言,此问题现已解决。希望这对将来遇到同样奇怪问题的人有用。