「翻譯」express-session 中間件

前言:最近在使用 express-session 中間件,查看使用的時候有些參數不是很清楚就花了一點時間把文檔翻譯了一下。javascript

其中經常使用設置中使人迷糊的是 resave 和 saveUnintialized 屬性,關於這兩個屬性,引用來自 CNODE 社區更通熟易懂的解釋html

resave : 是指每次請求都從新設置 session cookie,假設你的 cookie 是 10 分鐘過時,每次請求都會再設置 10 分鐘。
saveUninitialized: 是指不管有沒有 session cookie ,每次請求都設置個 session cookie ,默認給個標示爲 connect.sid。java

如下爲正文node

Installation

這是一個經過 npm registry 可用的 Node.js 模塊。使用如下 npm install 命令來完成安裝。git

$ npm install express-session
複製代碼

API

var session = require('express-session');
複製代碼

sessions(options)

使用給定選項建立一個 session 中間件。github

注意:只有 session ID 是保存在 cookie 中,Session 數據自己並非。Session 數據是存在服務端。redis

注意:從版本 1.5.0 起,本模塊再也不須要 cookie-parser 中間件來運行。本模塊如今直接在 req/res 上讀寫 cookies。當本模塊和 cookie-parser 的 secret 不一致時,使用 cookie-parser 可能會致使問題。shell

警告:默認的服務端 session 存儲,MemoryStore,特地沒有爲生產環境而設計。在大多數狀況下,它可能會致使內存泄漏,不會擴展超過單個進程,本是用於調試和開發。express

對於存儲列表,請查看兼容的 session 存儲npm

Options

express-session 在 options 對象中接收如下參數

cookie

session ID cookie 的設置對象。默認值爲 { path: '/', httpOnly: true, secure: false, maxAge: null }.

下列參數可選設置放入 cookie 對象。

cookie.domain

爲 Set-Cookie 屬性指定 domain。默認狀況下,沒有設置 domain,而且大多數客戶端會將 cookie 視爲僅應用於當前 domain。

cookie.expires

爲 Set-Cookie 屬性中的 Expires 指定 Date 對象。默認狀況下,沒有設置 expires,大多數客戶端會將視這個爲 "非持久化 cookie" 而且在像退出瀏覽器應用的場景下刪除該 cookie。

注意:若是 options 對象中同時設置了 expires 和 maxAge,那麼將被用到的是在對象中最後一個被定義的屬性。

注意:expires 選項不該該被直接設置;而應該只使用 maxAge 選項。

cookie.httpOnly

爲 Set-Cookie 屬性中的 HttpOnly 指定 boolean 值。當爲真值,HttpOnly 屬性被設置,不然不被設置。默認狀況下,HttpOnly 屬性是被設置的。

注意:設置該值爲 true 的時候要當心,由於服從協議的客戶端不會容許 JavaScript 在 document.cookie 中查看 cookie。

cookie.maxAge

指定當計算 Set-Cookie 屬性中的 Expires 時使用的 number (毫秒)值。這是經過獲取當前服務器時間並將 maxAge 毫秒數加入其中計算 Expires 日期時間來完成的。默認狀況下沒有設置 maxAge。

注意:若是 options 對象中同時設置了 expires 和 maxAge,那麼將被用到的是在對象中最後一個被定義的屬性。

cookie.path

爲 Set-Cookie 屬性指定 Path 值。默認狀況下該值被設爲 '/',也就是 domain 下的根路徑。

cookie.sameSite

爲 Set-Cookie 屬性中的 SameSite 指定 boolean 或者 string 值。其中,

  • true 會將 SameSite 屬性設爲 Strict 以實現嚴格的相同站點強制。
  • false 不會 SameSite 屬性。
  • 'lax' 會將 SameSite 屬性設置爲 Lax 以實現寬鬆的相同站點強制。
  • 'strict' 會將 SameSite 屬性設置爲 Strict 以實現嚴格的相同站點強制。

關於不一樣的強制級別的更多信息能夠在細則中找到tools.ietf.org/html/draft-…

注意:這是一個還未被徹底標準化的屬性而且未來可能發生變化。這意味着許多客戶端可能忽略這條屬性直到它們徹底理解它爲止。

cookie.secure

爲 Set-Cookie 屬性中的 Secure 指定 boolean 值。當爲真時,Secure 屬性被設置不然沒有設置。默認狀況下 Secure 屬性沒有被設置。

注意:當設置該值爲 true 的時候請當心,由於若是瀏覽器沒有創建 HTTPS 鏈接服從協議的客戶端將不會發送 cookie 返回給服務端。

請注意 secure: true 是推薦選項。然而,它須要啓用 HTTPS 的網站, 也就是 HTTPS 是 secure cookies 所必須的。若是 secure 被設置而你經過 HTTP 訪問你的站點,cookie 將不會被設置。若是你在代理後使用 node.js 而且設置 secure: true,你須要在 express 中設置 "trust proxy":

var app = express()
app.set('trust proxy', 1) // trust first proxy
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true }
}))
複製代碼

爲了在生產環境中使用 secure cookies,同時容許在開發環境中測試,下列是在 express 中基於 NODE_ENV 啓用此設置的示例:

var app = express()
var sess = {
  secret: 'keyboard cat',
  cookie: {}
}
 
if (app.get('env') === 'production') {
  app.set('trust proxy', 1) // trust first proxy
  sess.cookie.secure = true // serve secure cookies
}
 
app.use(session(sess))
複製代碼

cookie.secure 選項也能夠被設置成特殊值 "auto" 來讓這個設置自動和肯定的鏈接的安全性相匹配。若是站點能夠同時用作 HTTP 和 HTTPS 請當心使用這個設置,由於一旦 cookie 的 HTTPS 屬性被設置,cookie 不會再對 HTTP 可見。當 Express 的 "trust proxy" 被正確設置來簡化開發和生產配置的時候,這很是有用。

genid

調用來生成一個新的 session ID 的函數。提供一個返回 string 類型並將被用來做爲 session ID 的函數。當生成 ID 的時候若是你想用一些附加到 req 的值,該函數已給定 req 做爲第一個參數。

默認值是一個使用 uid-safe 庫來生成 ID 的函數。

注意:請當心生成惟一的 ID 以便你的 sessions 不會產生衝突。

app.use(session({
  genid: function(req) {
    return genuuid() // use UUIDs for session IDs
  },
  secret: 'keyboard cat'
}))
複製代碼
name

設置在 response 中(和從 request 中讀取)的 session ID 的 cookie 的 name。

默認值爲 "connect.sid"

注意:若是你有多個運行在相同 hostname(只是名字,也就是 localhost 或者 127.0.0.1;不一樣的協議(scheme) 和 端口(port) 不命名不一樣的主機名)上的應用,那麼你須要將 session cookie 彼此分開。最簡單的方法是每一個應用設置不一樣的 name。

proxy

當設置 secure cookies 的時候相信反向代理(經過 "X-Forwarded-Proto" 頭)。

默認值爲 undefined

  • true 表示 "X-Forwarded-Proto" 頭將會被使用。
  • false 表示只有存在直接的 TLS/SSL 鏈接時纔會忽略全部頭並認爲鏈接是安全的。
  • undefined 表示從 express 中使用 "trust proxy"。
resave

即便 session 在請求期間從未被修改過也強制 session 保存回 session 存儲(store)。根據你的存儲這多是必須的,可是這也可能創造競爭條件當客戶端發送兩個並行請求到你的服務端而且其中一個請求 A 對 session 做出的更改可能會在另外一個請求 B 結束時被覆蓋即便請求 B 沒有作任何更改(這個行爲取決於你用的 session 存儲)。

默認值爲 true,可是不推薦使用默認值,由於默認值未來會被更改。請研究此項設置並選擇適合你的用例的選項。通常來說,你會想選擇 false。

該如何知道該設置對個人 session 存儲來說是否是必須的呢?最好的方法是檢查你的存儲看它是否實現了 touch 方法。若是它實現了,那你能夠安全地設置 resave 爲 false。若是它沒有實現 touch 方法並且你的 store 在存儲的 sessions 中設定的 expiration 日期,那麼你可能須要設置 resave: false

rolling

強制在每次響應的時候設置一個 session 標誌符 cookie。expiration 從新被設置爲初始的 maxAge,重置 expiration 倒計時。

默認值爲 false。

注意:當該選項被設置爲 true 可是 saveUninitialized 選項被設置爲 false,則不會在具備未初始化的 session 響應中設置 cookie。

saveUninitialized

強制將未初始化的 session 保存回 store。當一個 session 是新的可是還未被修改時咱們說他是未初始化的。選擇 false 值對實現登陸 session 是有用的,由於它減小了服務器存儲的用量,遵照了設置 cookie 前須要許可的規則。選擇 false 值也有助於客戶端在沒有回話的狀況下發出過個並行請求的競爭條件。

默認值爲 true,可是不推薦使用默認值,由於默認值未來會被更改。請研究此項設置並選擇適合你的用例的選項。

注意:若是你正在結合 PassportJS 使用 Session,用戶經過身份驗證後PassportJS 將爲該用戶在 session 中添加一個空的 Passport 對象,這將會視爲對 session 的修改,致使 session 被保存。這已經在 PassportJS 0.3.0 中被修復。

secret

必設選項

這是用來給 session ID cookie 簽名的 secret。這能夠是單個 secret 的字符串也能夠是多個 secret 組成的數組。若是提供了一組 secrets,只有第一個元素會被用來給 session ID cookie 簽名,在驗證請求籤名的時候纔會考慮到全部元素。

store

session 存儲實例,默認爲一個新的 MemoryStore 實例。

unset

控制取消設置 req.session 的結果(經過刪除,設爲 null,等等)。

默認值爲 'keep'

  • 'destroy' 表示當響應結束的時候 session 將會被銷燬(刪除)。
  • 'keep' 表示在 store 中的 session 會被保留,可是在請求期間作的修改將會被忽略不會被保存。

req.session

存儲或者訪問 session 數據,只須要使用請求屬性 req.session,該屬性(一般)由 store 序列化爲 session,因此通常來講嵌套對象也能夠接受。下面的示例是一個基於特定用戶的視圖計數器:

// Use the session middleware
app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
 
// Access the session as req.session
app.get('/', function(req, res, next) {
  if (req.session.views) {
    req.session.views++
    res.setHeader('Content-Type', 'text/html')
    res.write('<p>views: ' + req.session.views + '</p>')
    res.write('<p>expires in: ' + (req.session.cookie.maxAge / 1000) + 's</p>')
    res.end()
  } else {
    req.session.views = 1
    res.end('welcome to the session demo. refresh!')
  }
})
複製代碼

Session.regenerate(callback)

要從新生成 session 只須要調用這個方法。完成後一個新的 SID 和 Session 實例將會被初始化在 req.session 而且 callback 會被調用。

req.session.regenerate(function(err) {
  // will have a new session here
})
複製代碼

Session.destroy(callback)

銷燬 Session 並取消設置 req.session 屬性。完成後將調用 callback。

req.session.destroy(function(err) {
  // cannot access session here
})
複製代碼

Session.reload(callback)

從 store 從新載入 session 數據並從新填充 req.session 對象。完成後將調用 callback。

req.session.reload(function(err) {
  // session updated
})
複製代碼

Session.save(callback)

將 session 保存回 store,用內存中的內容替換 store 中的內容(儘管 store 可能還會作其餘的事情—參閱 store 的文檔以瞭解其確切的行爲)。

若是 session 數據被改變了這個方法會在 HTTP 響應的末尾自動被調用(儘管這個行爲能夠被中間件構造器中的多種選項所改變)。所以,通常來說這個方法不須要被手動調用。

存在一些調用這個方法會頗有用的狀況,好比重定向,長期請求(long-lived requests)或着 WebSockets。

req.session.save(function(err) {
  // session saved
})
複製代碼

Session.touch(callback)

更新 .maxAge 屬性。通常來說這個方法不須要被調用由於 session 中間件爲你執行了這個操做。

req.session.id

每個 session 都有一個與之關聯的惟一 ID。該屬性是 req.sessionID 的別名並且沒法修改。該屬性已被添加以使 session ID 能夠從 session 對象中訪問。

req.session.cookie

每個 session 都有一個惟一的 cookie 與之伴隨。這容許你更改每一個訪問者的 session cookie。例如咱們能夠設置 req.session.cookie.expires 爲 false 來使 cookie 僅在用戶-代理的持續時間中保留。

Cookie.maxAge

req.session.cookie.maxAge 將以毫秒數返回剩餘的時間,咱們也能夠從新分配一個新值來適當地調整 .expires 屬性。如下代碼是等效的:

var hour = 3600000
req.session.cookie.expires = new Date(Date.now() + hour)
req.session.cookie.maxAge = hour
複製代碼

例如當 maxAge 被設置爲 60000(一分鐘)時,三十秒後它將返回 30000 知道當前的請求已完成,此時調用 req.session.touch() 將會重設 req.session.maxAge 爲它的初始值。

req.session.cookie.maxAge // => 30000
複製代碼

req.sessionID

要拿到載入的 session 的 ID,訪問請求的屬性 req.sessionID。當 session 被載入或被建立的時候這僅是一個只讀的值。

Session Store Implementation

每個 session store 必須是一個 EventEmitter 而且實現特定的方法。下列的方法是必需,推薦和可選的列表。

  • 必需的方法是此模塊將會始終在 store 中調用的方法。
  • 推薦的方法是若是可用此模塊將會在 store 中調用的方法。
  • 可選的方法是此模塊根本不會調用的方法

有關示例實現請查看 connect-redis 倉庫。

store.all(callback)

可選

該可選方法用於以數組形式獲取 store 中的全部 session。回調方法應該使用爲 callback(error, sessions)

store.destroy(sid, callback)

必需

該必需方法根據給定的 session ID 來銷燬(刪除)store 中的 session。session被刪除後回調函數應該使用爲 callback(error)

store.clear(callback)

可選

該可選方法用於刪除 store 中的全部 session。store 清空後回調函數應該使用爲 callback(error)

store.length(callback)

可選

該可選方法用於獲取 store 中全部 session 的個數。回調函數應該使用爲 callback(error, len)

store.get(sid, callback)

必需

該必需方法根據給定的 session ID 從 store 中獲取 session。回調函數應該使用爲 callback(error, session)

若是找到 session 回調函數中的 session 參數應該爲一個 session 對象,不然若是沒有找到 session(而且也沒有錯誤)應該爲 null 或 undefined。當 error.code === 'ENOENT' 表現爲 callback(null, null) ,這是一種特殊狀況。

store.set(sid, session, callback)

必需

該必需方法根據給定的 session ID 和 session 對象將 session 存入 store。session 存入 store 後回調函數應該使用爲 callback(error)

store.touch(sid, session, callback)

推薦

該推薦方法根據給定的 session ID 和 session 對象 "觸碰" 給定的 session 對象。session 被 "觸碰" 後回調函數應該使用爲 callback(error)

該方法主要用於 store 自動刪除空閒 session,並將此方法用於向 store 發送給定 session 處於活動狀態的信號,可能回重置空閒計時器。

Compatible Session Stores

下列的模塊是實現了一個和本模塊兼容的 session store。請提出 PULL REQUEST 來添加其餘的模塊 :)

本處僅列出兩處 store 實現,更多請查看原文檔

connect-db2: 一個使用 ibm_db 模塊建成的基於 IBM DB2 的 session store。

connect-mongo: 一個基於 SQL Server 的 session store。

Example

一個簡單使用 express-session 來爲用戶存儲頁面訪問的例子:

var express = require('express')
var parseurl = require('parseurl')
var session = require('express-session')
 
var app = express()
 
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))
 
app.use(function (req, res, next) {
  if (!req.session.views) {
    req.session.views = {}
  }
 
  // get the url pathname
  var pathname = parseurl(req).pathname
 
  // count the views
  req.session.views[pathname] = (req.session.views[pathname] || 0) + 1
 
  next()
})
 
app.get('/foo', function (req, res, next) {
  res.send('you viewed this page ' + req.session.views['/foo'] + ' times')
})
 
app.get('/bar', function (req, res, next) {
  res.send('you viewed this page ' + req.session.views['/bar'] + ' times')
})
複製代碼

License

MIT

Keywords

none

相關文章
相關標籤/搜索