「翻译」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

相关文章
相关标签/搜索