注意
本页面生成自 cookie-session README。cookie-session
简单的基于 cookie 的会话中间件。
用户会话可以通过两种主要方式与 cookie 一起存储:在服务器上或在客户端上。此模块将会话数据存储在客户端的 cookie 中,而像 express-session 这样的模块只在客户端的 cookie 中存储会话标识符,并将会话数据存储在服务器上,通常在数据库中。
以下几点可以帮助您选择使用哪种方式:
cookie-session
不需要服务器端的任何数据库/资源,但总会话数据不能超过浏览器的最大 cookie 大小。cookie-session
可以简化某些负载均衡场景。cookie-session
可以用于存储“轻量”会话,并包含一个标识符以查找数据库支持的辅助存储,从而减少数据库查找。
注意 本模块不加密 cookie 中的会话内容,仅提供签名以防止篡改。客户端可以通过检查 cookie 的值来读取会话数据。未经加密的秘密数据不应设置在 req.session
中,或者应改用服务器端会话。
注意 本模块不阻止会话重放,因为设置的过期时间仅限于 cookie;如果您的应用程序关注此问题,您可以在 req.session
对象中存储一个过期日期并在服务器上验证它,并根据应用程序需要实现任何其他扩展会话的逻辑。
安装
这是一个通过 npm registry 提供的 Node.js 模块。使用 npm install
命令进行安装。
$ npm install cookie-session
API
var cookieSession = require('cookie-session')
var express = require('express')
var app = express()
app.use(cookieSession({
name: 'session',
keys: [/* secret keys */],
// Cookie Options
maxAge: 24 * 60 * 60 * 1000 // 24 hours
}))
cookieSession(options)
使用提供的选项创建一个新的 cookie 会话中间件。此中间件将属性 session
附加到 req
,req
提供一个表示已加载会话的对象。如果请求中未提供有效的会话,则此会话是一个新会话;否则,它是从请求中加载的会话。
如果 req.session
的内容被修改,中间件将自动向响应添加一个 Set-Cookie
头部。请注意,除非会话中有内容,否则响应中不会有 Set-Cookie
头部(因此不会为特定用户创建会话),所以请务必在获得可存储用于会话的识别信息后,立即向 req.session
添加一些内容。
选项
Cookie 会话在选项对象中接受以下属性。
name
要设置的 cookie 名称,默认为 session
。
keys
用于签名和验证 cookie 值的键列表,或一个已配置的 Keygrip
实例。设置的 cookie 总是用 keys[0]
签名,而其他键则用于验证,从而允许密钥轮换。如果提供了 Keygrip
实例,它可用于更改签名参数,例如签名算法。
secret
如果未提供 keys
,则用作单个键的字符串。
Cookie 选项
其他选项将传递给 cookies.get()
和 cookies.set()
,允许您控制安全性、域、路径和签名等设置。
选项还可以包含以下任何内容(完整列表请参阅 cookies 模块文档
maxAge
: 一个数字,表示从Date.now()
起的过期毫秒数expires
: 一个Date
对象,指示 cookie 的过期日期(默认为会话结束时过期)。path
: 一个字符串,指示 cookie 的路径(默认为/
)。domain
: 一个字符串,指示 cookie 的域(无默认值)。partitioned
: 一个布尔值,指示是否在 Chrome 中为 CHIPS 更新分区 cookie(默认为false
)。如果为 true,则来自嵌入式站点的 cookie 将被分区,并且只能从创建它的同一个顶级站点读取。priority
: 一个字符串,指示 cookie 优先级。可以设置为'low'
、'medium'
或'high'
。sameSite
: 一个布尔值或字符串,指示 cookie 是否为“同站”cookie(默认为false
)。可以设置为'strict'
、'lax'
、'none'
或true
(映射到'strict'
)。secure
: 一个布尔值,指示 cookie 是否仅通过 HTTPS 发送(HTTP 默认为false
,HTTPS 默认为true
)。如果设置为true
且 Node.js 未直接通过 TLS 连接,请务必阅读如何在代理后设置 Express,否则 cookie 可能无法正确设置。httpOnly
: 一个布尔值,指示 cookie 是否仅通过 HTTP(S) 发送,并且不可用于客户端 JavaScript(默认为true
)。signed
: 一个布尔值,指示 cookie 是否需要签名(默认为true
)。overwrite
: 一个布尔值,指示是否覆盖以前设置的同名 cookie(默认为true
)。
req.session
表示给定请求的会话。
.isChanged
如果会话在请求期间已更改,则为 true
。
.isNew
如果会话是新的,则为 true
。
.isPopulated
确定会话是否已填充数据或为空。
req.sessionOptions
表示当前请求的会话选项。这些选项是中间件构建时提供的选项的浅克隆,可以更改以在每个请求的基础上更改 cookie 设置行为。
销毁会话
要销毁会话,只需将其设置为 null
req.session = null
保存会话
由于会话的全部内容都保存在客户端 cookie 中,因此会话通过在 Set-Cookie
响应头中写入 cookie 来“保存”。如果 Node.js 响应头写入客户端时会话已更改且会话未被销毁,则会自动完成此操作。
示例
简单的视图计数器示例
var cookieSession = require('cookie-session')
var express = require('express')
var app = express()
app.set('trust proxy', 1) // trust first proxy
app.use(cookieSession({
name: 'session',
keys: ['key1', 'key2']
}))
app.get('/', function (req, res, next) {
// Update views
req.session.views = (req.session.views || 0) + 1
// Write response
res.end(req.session.views + ' views')
})
app.listen(3000)
每个用户的粘性最大寿命
var cookieSession = require('cookie-session')
var express = require('express')
var app = express()
app.set('trust proxy', 1) // trust first proxy
app.use(cookieSession({
name: 'session',
keys: ['key1', 'key2']
}))
// This allows you to set req.session.maxAge to let certain sessions
// have a different value than the default.
app.use(function (req, res, next) {
req.sessionOptions.maxAge = req.session.maxAge || req.sessionOptions.maxAge
next()
})
// ... your logic here ...
延长会话过期时间
如果会话内容未更改,本模块不会发送 Set-Cookie
头部。这意味着要延长用户浏览器中会话的过期时间(例如,响应用户活动),需要对会话进行某种修改。
var cookieSession = require('cookie-session')
var express = require('express')
var app = express()
app.use(cookieSession({
name: 'session',
keys: ['key1', 'key2']
}))
// Update a value in the cookie so that the set-cookie will be sent.
// Only changes every minute so that it's not sent with every request.
app.use(function (req, res, next) {
req.session.nowInMinutes = Math.floor(Date.now() / 60e3)
next()
})
// ... your logic here ...
使用自定义签名算法
此示例展示了如何创建自定义的 Keygrip
实例作为 keys
选项,以提供密钥和额外的签名配置。
var cookieSession = require('cookie-session')
var express = require('express')
var Keygrip = require('keygrip')
var app = express()
app.use(cookieSession({
name: 'session',
keys: new Keygrip(['key1', 'key2'], 'SHA384', 'base64')
}))
// ... your logic here ...
使用限制
最大 Cookie 大小
因为整个会话对象都被编码并存储在 cookie 中,所以可能会超出不同浏览器上的最大 cookie 大小限制。RFC6265 规范建议浏览器应允许
每个 cookie 至少 4096 字节(按 cookie 名称、值和属性长度的总和计算)
实际上,此限制在不同浏览器之间略有不同。请在此处查看浏览器限制列表。作为经验法则,每个域不要超过 4093 字节。
如果您的会话对象编码后大到超过浏览器限制,在大多数情况下,浏览器将拒绝存储 cookie。这将导致来自浏览器的后续请求要么 a) 没有任何会话信息,要么 b) 使用足够小、未超过 cookie 限制的旧会话信息。
如果您发现您的会话对象达到了这些限制,最好考虑您的会话中的数据是否应该从服务器上的数据库加载,而不是在每个请求中与浏览器之间传输。或者切换到替代会话策略。