前面是瞎扯,代碼在后面。
前言
http 請求是無狀態的,什么是無狀態呢,就是你先后向服務器發送兩個請求,服務器那邊比較糊涂,自己是沒有辦法識別這兩個請求是否是同一個用戶發送來的。
也就是說,我上一秒給你五毛錢你下一秒就不認賬的意思。
為了避免這種情況發生,我們告訴服務器,對岸的朋友來的時候,你給他一個簽名,告訴他,下次帶著簽名過來,確認一下是不是對的人。
當然,這個簽名也是有 有效期 的。
所以,我們開發者就在用戶第一個請求過來的時候存起來,然后給用戶一個對應的標識,這個標識也是有 有效期 的,用戶下一個請求過來的時候判斷一下這個標識是否對應是否符合條件,if true next else redirect ,就這樣。
當然,程序員是無敵的嘛,我們有一百種改變世界的辦法,如今,我已經找到了這樣的辦法,本篇簡書就到此結束,謝謝大家!!!
session
What!!!看到這里你還問我 session 是什么?WTF
嘿siri,session 是什么東東
Session:在計算機中,尤其是在網絡應用中,稱為“會話控制”。Session 對象存儲特定用戶會話所需的屬性及配置信息。這樣,當用戶在應用程序的 Web 頁之間跳轉時,存儲在 Session 對象中的變量將不會丟失,而是在整個用戶會話中一直存在下去。當用戶請求來自應用程序的 Web 頁時,如果該用戶還沒有會話,則 Web 服務器將自動創建一個 Session 對象。當會話過期或被放棄后,服務器將終止該會話。Session 對象最常見的一個用法就是存儲用戶的首選項。例如,如果用戶指明不喜歡查看圖形,就可以將該信息存儲在 Session 對象中。有關使用 Session 對象的詳細信息,請參閱“ASP 應用程序”部分的“管理會話”。注意 會話狀態僅在支持 cookie 的瀏覽器中保留。
嘿siri,自殺
......
簡單的說,session 可以用來維持會話,服務器每天要接受 XXX 個請求,上面說了 http 是無狀態的,哪能分得出誰是誰,不過 session 可以用來幫助服務器區分哪些請求對應哪些用戶,對的,就這樣,不知道有沒有說清楚~
舉個例子吧,剛學編程時會接觸到登陸功能,登錄成功的時候一定要存一個 session 然后返回到用戶的 cookie 中,用來保持這個用戶的會話信息,用戶下個請求攜帶著 cookie 信息來的時候判斷一下該用戶是否登錄,然后在進行后續的一頓操作,嗯,就這樣 ~ 還有不懂得可以在網上找一些資料更詳細的了解一下這一塊 ~
基于內存來管理 session
剛開始我們為了方便快捷會把 session 存在服務器的內存中,就像下面這樣:
變動的地方會用 start 和 end 標識出來
// app.js 文件中
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
// start
// 安裝 express-session 模塊 并引入
var session = require('express-session');
// end
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
// start
// session 的一些配置
app.use(session({
secret: 'zz',
cookie:{maxAge:60000},
resave: false,
saveUninitialized: true
}));
// end
app.use('/static',express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
// ./routes/index.js 文件中
var express = require('express');
var router = express.Router();
/* GET home page. */
// 用來為這個用戶存儲一個 session
router.get('/a', function(req, res, next) {
var a = Math.floor(Math.random()*10)+''
req.session.user = a
res.send(a)
});
// 在頁面上打印自己在 session 中存儲的信息
router.get('/b', function(req, res, next) {
req.session.touch();
res.send(req.session.user)
});
module.exports = router;
上面這種基于內存來存儲 session 方法唯一的好處是方便省事,適合初學,但是也存在好多缺點。比如說:
- 如果用戶量比較大,session 會把內存占滿
- 服務器掛了,然后重啟后 session 就不存在了
- 項目部署在多臺服務器的集群中,就不好使了
......
基于 mongo 來管理 session
不一定要用 mongo 來管理 session,你們可以用 redis 、 memcache 、mysql 等都可以,我這里用 mongo 是因為電腦里面剛裝了個 mongo , 就順手拿來用了。
話不多說,先上代碼為敬~
// app.js 文件中, ./routes/index.js 文件不變
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
// start
// 引入 這兩個 第三方庫
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
// end
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
// start
// 設置 session 存儲的一些配置選項
app.use(session({
secret: 'zz',
cookie: {
maxAge: 10000
},
resave: false,
saveUninitialized: true,
store: new MongoStore({
url:'mongodb://localhost/ims',
collection:'sessions'
})
}))
// end
app.use('/static',express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
上圖中可以看到,mongo 中存儲了一條 session 記錄,這樣你如果項目跑在多臺服務器的話,這條 session 記錄就可以在這多臺服務器中共享,即使其中某臺服務器掛了也不影響 session 的存儲,從而來達到 session 持久化存儲。
總結
基于內存的 session 存儲
0.如果用戶量比較大,session 會把內存占滿
1.服務器掛了,然后重啟后 session 就不存在了
2.項目部署在多臺服務器的集群中,就不好使了
......
session 持久化存儲
0.提高服務器內存的利用率
1.在多臺服務器同時對外提供服務的集群系統中,可以共享 session
2.當某臺服務器掛掉后,重啟以后還可以使用之前未過期的 session
這么枯燥乏味的文章能看到這里已經很棒了,這些東西都太抽象了,剛開始肯定不好理解,建議多查詢一些資料,親自試驗一下,感受一下成功的喜悅,嗯哼~