express-session
是express中的一個處理session
的中間件,能夠說是express
中最多見的中間件之一了.javascript
因爲會話管理依賴cookie
的使用,因此它的api中有不少用於控制cookie
的部分.java
總的來講express-session
有以下的特色:redis
本文中使用的版本爲1.15.6
.mongodb
npm install express-session --save
const express = require('express'); const app = new express(); const expressSession = require('express-session'); // 使用express-session app.use(expressSession({ secret:'hello world',// cookie簽名 這個屬性是必須的 具體配置和`cookie-parser`同樣 saveUninitialized:true, // 是否自動初始化 默認爲true resave:false,// 當用戶session無變化的時候依然自動保存 cookie:{ // cookie的信息具體操做和`cookie-parser`同樣 maxAge:1800000// 30分鐘後過時 }, rolling:true// 每次請求的時候覆寫cookie }))
在express-session
文檔中有以下的一句說明:chrome
Note Session data is not saved in the cookie itself, just the session ID. Session data is stored server-side.
Session中包含的數據不會保存在cookie中,僅僅是在cookie中保存了一個SessionId而已.實際的session的數據保存在服務端.數據庫
簡單理解就是一個Map,鍵對應的是session id
值保存在cookie
中,值對應的是用戶保存在服務端的數據.express
建立express-cookie
參數基本分爲兩種.npm
cookie
的設置express-session
的設置cookie設置一覽:api
app.use(expressSession({ secret:'hello world', // cookie 簽名必須有不然會報錯 cookie:{ domain:<參數>, expires:<參數>, httpOnly:<參數>, path:<參數>, sameSite:<參數>, secure:<參數>, maxAge:1800000 } }));
而這些對應的參數就是服務端對於cookie的寫入參數,至於各個參數是什麼意思參考下面的文章:瀏覽器
https://developer.mozilla.org...
express-session部分設置:
app.use(expressSession({ secret:'hello world', // cookie 簽名必須有不然會報錯 genid:function (request) { // 用於替換掉默認ID生成的函數 第一個參數爲reqeust return '隨機id' }, name:'connect.sid',// 每次響應中向cookie中起始的內容,默認起始爲`connect.sid`, proxy:true,// 對於cookie使用secure後,在傳遞的過程當中相信反向代理服務器,默認爲undefined只相信正向代理 resave:true,// 在一次會話中不管是否session被改變都會進行強制的儲存 rolling:true,// 在每次會話中的響應中都覆寫一次cookie,重置倒計時 saveUninitialized:true,// 將一個新建立還未修改的會話進行儲存,默認爲true store:object// 一個儲存對象,默認使用的是`MemoryStore`這個存儲器 unset:'keep'// 控制沒有設置`req.session`時候的行爲(使用delete刪除或者賦值null),默認'keep'會話期間不會保留,'destroy'會話完成後刪除. }));
在request.session
上掛載的session
對象,除了有你添加的內容外,還有默認的方法存在:
req.session.regenerate(function(err) { // 調用這個方法重新生成一個新的會話,完成後觸發 })
req.session.destroy(function(err) { // 刪除這個會話,完成後觸發 })
req.session.reload(function(err) { // 重新加載session數據,完成後觸發回調 })
req.session.save(function(err) { // 使用當前內存中的數據保存到儲存器中 // 默認在會話結束的時候就會自動調用這個方法 })
req.session.touch() // 更新cookie中的maxAge,通常不須要手動操做,交由中間件
一樣的在session
實例上也有不少屬性:
req.session.id // 保存惟一的會話id值,不可修改 req.session.cookie // 以鍵值對的形式保存cookie的原始數據 req.session.cookie.maxAge // 以毫秒的形式返回剩餘存活時間 req.sessionID // 保存惟一的會話id,只讀
一個簡單的登陸例子:
const express = require('express'); const app = new express(); const expressSession = require('express-session'); const userDb = new Map(); app.use(expressSession({ secret:'hello world', saveUninitialized:true, resave:false, cookie:{ maxAge:1800000 }, rolling:true, })); app.get('/login', (request, response) => { const id = request.query.id, pwd = request.query.pwd; if(id && pwd){ if(userDb.has(id+pwd)){ response.send('該用戶已登陸'); }else{ request.session.userId = id+pwd; userDb.set(id+pwd,id); response.redirect('/'); } }else{ response.send('請輸入正確的賬號和密碼'); } }); app.get('/logout',(request, response)=>{ const userId = request.session.userId; request.session.destroy((err)=>{ if(err || !userDb.has(userId)){ response.send('登出失敗'); }else{ userDb.delete(userId); response.send('登出成功'); } }); }); app.get('/',(request, response)=>{ if(request.session.userId && userDb.has(request.session.userId)){ response.send(`歡迎回來${userDb.get(request.session.userId)}`); }else{ response.send('還未登陸'); } }); app.use((request, response) => { response.send('404 not found'); }); app.listen(8888, '127.0.0.1');
在瀏覽器中依次輸入如下url來模擬登陸行爲:
localhost:8888/ localhost:8888/login?id=ASCll&pwd=123456 localhost:8888/ localhost:8888/logout localhost:8888/
我在chrome瀏覽器下運行上面的例子屢次後發現一個問題,瀏覽器會進行預讀取網頁來提升性能,也就是說在瀏覽器中當我url輸入到以下的地方時:
localhost:8888/logo
根據我之間屢次進入這個頁面瀏覽器會提早訪問這個頁面localhost:8888/logout
,而致使服務器直接刪除session
等到真正進入到頁面的時候已是第二次加載頁面了,致使每次登出都顯示失敗.
但願有經驗的朋友能給出一個合理的解決方案.
當express-session
和cookie-parser
一塊兒使用的時候對於cookie
的簽名必須一致.
express-session
的存儲實例是能夠更換的,默認使用MemoryStore
只適合於測試和開發使用,生產環境必需要使用其餘的儲存實例,不然會出現內存碎片問題,在官方文檔中給出了已經實現的接口,能夠對接redis
以及mongodb
等數據庫.
該列表在官方文檔的最後:
npm地址