我正在創建一個電子商務網站,我將所有資料存盤在資料庫以及會話存盤中。對于已登錄的用戶,只有登錄憑證被存盤在會話存盤中。因此,每當網站第一次運行時,應該從資料庫中獲取我們從會話存盤中獲得的資料,但如果我為此目的使用一個中間件,它是無效的,因為中間件在每個請求上運行。那么,有什么辦法可以解決這個問題,或者有什么更好的解決方案可以更有效地解決這個問題?還有,你可能想知道為什么我不直接在會話存盤中存盤資料。所以,問題是,當我從會話存盤中獲取資料時,它不會以mongoose模型的形式回傳,所以我必須呼叫資料庫一次。我使用了 mongo store、express、node 和 ejs.
。這是我在索引檔案中使用的中間件,用于在mongoose模型中使用登錄時存盤在會話存盤中的ID從資料庫獲取資料。
app.use(async(req, res, next) => {
try {
if(req.session.userid) {
req.user = await user.findById(userid)
}
} catch(err) {
res.redirect('/' req.oldUrl '? err=UserNotFound')
}
next()
})
app.use(session({
secret: 'secret',
saveUninitialized: false,
resave: false,
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 100,
secure: false。
},
store: store
}))
這是我的mongoose模型
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const userschema = new Schema({
Name : {
型別。String。
required : true。
},
Email : {
型別。String,
required : true.
},
Password : {
型別。String,
required : true.
},
IsSeller : {
型別。Boolean,
defualt : false.
},
Shopname : {
Type : String,
default : "-".
},
Cart : {
Items : [
{
productId : {
type : Schema.Types.ObjectId,
ref : 'product'。
required : true.
},
數量 : {
型別。Number,
required : true
}
}
]
},
Myproducts : {
專案:[
{
productId : {
型別。Schema.Types.ObjectId,
ref : 'product'。
required : true.
},
數量 : {
型別。Number,
required : true
}
}
]
},
Sdate : {
型別。String,
default : "-"/span>.
}
})
module.exports = mongoose.model('user', userschema)
uj5u.com熱心網友回復:
如果你不想把它作為一個普通的中間件,你可以在你的一個控制器中直接使用express-sessions。如果你在登錄時設定了一個會話cookie,并且只在用戶下次登錄時檢查它,確保用戶在標簽或瀏覽器關閉時被注銷,或者在一定時間后,如果你想保持更多的靈活性,讓用戶在X時間內繞過登錄表單。
// in app.js
const session = require('express-sessions' )
const MongoStore = require('connect-mongodb-session') (session)
const store = new MongoStore( {
uri: MONGO_URI.
collection: 'session'
app.use(session, {
secret: 'myL0ngSecretXXX'。
resave: false,
saveUninitialized: false,
存盤
})
//在你的登錄控制器中。
exports.setSession = (req, res, next) => {
req.session.isAuthenticated = true //this saves a session cookie client side.
res.redirect('/dashboard'/span>)
}
// Router:
router.post('/login'/span>, loginService)
//登錄服務。
const { setSession } = require(' ./controllers/login')
//其他要求...。
exports.loginService = catchAsync(async(req, res, next)=> {
const allowedFields = ['email'/span>, 'password'/span>]
if (!checkFieldsStrict(req. body, allowedFields) || (isEmptyRequest(req.body)) {
return next(new ErrorResponse(`Invalid request. `, 400)
}
const { email, password } = req.body
if (!email || !password) {
return next(new ErrorResponse(`Please provide your email and password. `, 400)
}
const user = await User.findOne({
where: { email },
})
if (!user) {
//不要透露用戶是未知的:。
return next(new ErrorResponse(`Invalid credentials. `, 401)
}
const passwordMatch = await comparePasswords( password, user.password)
if (! passwordMatch) {
return next(new ErrorResponse(`Invalid credentials. `, 401)
}
setSession()
//也許除了會話之外,還可以發回一個令牌?。
})
uj5u.com熱心網友回復:
首先,你可以通過不在每個請求上重新運行中間件來使中間件更有效率。 只要把用戶保存在會話本身就可以了。 據推測,userId和用戶之間的關系永遠不會改變,所以每當你第一次得到userId時,只要得到user并將其保存在會話本身。 然后,你在每個會話中只查詢一次資料庫。
app.use(async (req, res, next) => {
try {
if(req.session.userid & & !req.session.user) {
req.session.user = await user.findById(userid)
}
} catch(err) {
res.redirect('/' req.oldUrl '? err=UserNotFound')
return。
}
next()
});
如果你絕對需要req.user中的資料,而不是req.session.user,你也可以讓中間件設定:
app.use(async (req, res, next) => {
try {
if(req.session.userid & & !req.session.user) {
req.session.user = await user.findById(userid)
}
} catch(err) {
res.redirect('/' req.oldUrl '? err=UserNotFound')
return。
}
//populate req.user if user is available.
if (req.session.user) {
req.user = req.session.user。
}
next()
});
如果user物件中的某些資料可能會隨著時間的推移而發生變化,而你又想獲得該特定資訊的新鮮片段,那么你可以放一個DB請求來獲取這些特定路線中絕對最新的用戶物件。 這樣,你只在用戶最初登錄時和路由絕對需要資料庫中的最新資訊時才會訪問資料庫,而不是在每一次請求中。
哦,還有一件事。 在你呼叫res.redirect()之后,你需要從中間件中回傳,而不是呼叫next(),因為你已經完成了對該請求的處理,并且不希望再對該請求進行路由處理。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/319167.html
標籤:
