我正在開發一個非常簡單的社交媒體應用程序,用戶可以在其中註冊、登入、創建帖子、編輯他們的個人資料和帖子、刪除帖子以及完全刪除自己。
應適當地建立和使用透過 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 更新,這完全把我搞砸了。
就目前情況而言,此票證現已解決。希望這對將來遇到同樣奇怪問題的人有用。
到目前為止,我找到了一個令我難以置信的解決方案:在我的 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 更新,這完全把我搞砸了。
就目前情況而言,此問題現已解決。希望這對將來遇到同樣奇怪問題的人有用。