Express Session 处理中间件 express-session

 2017年07月16日    311     声明


express-session是Express官方提供的一个用于处理Session的中间件,在Express应用中引入express-session后,可以很方便的在req.session中访问Session。

  1. 使用express-session
  2. express-sessionAPI

1. 使用express-session

安装

express-session可以通过npm安装:

$ npm install express-session --save

使用

安装后,可以在Experss应用的启动文件(一般是app.js)中,做为中间件引用express-session后。

通过app.use()方法引入express-session中间件:

var session = require('express-session');

// 挂载 session 中间件
app.use(session({ secret: 'a secret', cookie: { maxAge: 60000 }}));

引入express-session中间件后,就可以在其后的路由中通过req对象操作Session。

以下是一个通过Session记录访问页面访问次数的示例:

// 通过 req.session 访问 session
app.get('/', (req, res, next) => {
  var sess = req.session
  if (sess.views) {
    sess.views++
    res.setHeader('Content-Type', 'text/html')
    res.write('<p>views: ' + sess.views + '</p>')
    res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>')
    res.end()
  } else {
    sess.views = 1
    res.end('welcome to the session demo. refresh!')
  }
})


2. express-sessionAPI

var session = require('express-session');

2.1 session(options)

通过指定参数对象options创建一个Session中间件。

express-session被导出为一个工厂方法,通过require引用可获取该方法,并可通过该方法创建一个Session中间件。

Session 中间件的一些说明

Session 数据并不存储在 Cookie中,而是存储在服务端,Cookie仅会存储一个session ID

1.5.0版本起,express-session会支持在req/res中操作Cookie,而不在依赖cookie-parser中间件。当使用cookie-parser时,应该确保两个中间件的secret一致,否则可能会出现问题。

express-session在服务端默认会使用MemoryStore存储 Session,这样在进程重启时会导致Session丢失,且不能多进程环境中传递。在生产环境中,应该使用外部存储,以确保 Session 的持久性。以下是官方推荐的一些Session存储:


2.2 Options

在使用express-session创建中间件时,我们会传入一个options对象,在这个对象中可以包含以下属性:

  • cookie - Object,用于设置存储session ID的Cookie,默认值是{ path: '/', httpOnly: true, secure: false, maxAge: null }

    cookie中可以包含以下选项

    • cookie.domain - 指定Set-CookieDomain属性。默认域名不会设置,设置后,Cookie仅会对指定的域名生效。
    • cookie.expires - Date对象,用于指定Set-CookieExpires属性。默认不会设置超时属性,而客户端会实现为"non-persistent cookie"。

      当同时设置expiresmaxAge时,将会使用后设置的一个。更推荐使用maxAge,而不显示的设置expires

    • cookie.httpOnly - boolean值,用于指定Set-CookieHttpOnly属性。默认HttpOnly属性会被设置。

      设置为true时,将不允许JavaScript通过document.cookie访问Cookie

    • cookie.maxAge - number(毫秒),用于指定Set-CookieExpires属性。设置后,Cookie将在指定时间后失效。
    • cookie.path - 用于指定Set-CookiePath属性。默认会被设置为'/',即当前域名的根路径。
    • cookie.sameSite - booleanstring值,用于指定Set-CookieSameSite属性:
      • trueSameSite设置等同于'strict'
      • false时将不会设置SameSite
      • 'lax'将设置SameSiteLax,对同一站点松散执行
      • 'strict'将设置SameSiteStrict,对同一站点严格执行

      详细参考:"Strict" and "Lax" enforcement

    • cookie.secure - boolean值,用于指定Set-CookieSecure属性。默认情况下,不会设置该值。

      将设置为true时,不使用HTTPS连接时,当客户端将不会回传Cookie。

      推荐使用secure: true设置,但这时站点应该HTTPS,如果使用HTTPCookie不会被设置。这时,如果使用了代理,则应该在Expres中设置"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 }
      }))
  • genid - 一个函数,用于生成新的Session ID。该函数会将req做为第一个参数,而生成的ID,也可以添加到req上。

    默认情况下,会使用uid-safe库生成ID。如果要自定义生成,可以像下面这样:

    app.use(session({
      genid: function(req) {
        return genuuid() // use UUIDs for session IDs
      },
      secret: 'keyboard cat'
    }))
  • name - session ID的Cookie名,该值会设置到response中,并可在request中读取。默认值为'connect.sid'
  • proxy - 设置安全Cookie时,信任反向代理。

    其默认值为undefined,可设置值如下:

    • true会使用"X-Forwarded-Proto"头
    • false忽略所有请求头,只有使用TLS/SSL时才会认为是安全连接
    • undefined使用Express中的"trust proxy"
  • resave - 强制将 session 保存回session存储区,即使在请求期间session从不被修改。该值默认为true
  • rolling - 强制在每个response中Cookie中设置session标识符。到期时间会被重置为原始的maxAge

    当此选项被设置为true,而saveUninitialized设置为false时,未初始化的session的cookie将不会在response中设置。

  • saveUninitialized - 强制将未初始的session保存到存储中。Session在新创建而未修改时,是未初始化状态。
  • secret - 必须项。该值用于session ID的cookie签名。该值可以是单个字符串,或是多个字符串数组。当使用数组时,只有第一个会被用于签名,而所有值都会被用于request中的签名。
  • store - session的存储实例,默认为MemoryStore
  • unset - req.session释放结果控制。默认为'keep'
    • 'destroy' - Session会在response结束后删除
    • 'keep' - Session会被保存在存储中,但在请求期间将不能修改和保存


2.3 Session对象

req.session - 访问Session

正确设置express-session中间件后,可以通过req.session属性来存储或访问Session数据,Session会被序列化为JSON存储。

// 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) {
  var sess = req.session
  if (sess.views) {
    sess.views++
    res.setHeader('Content-Type', 'text/html')
    res.write('

views: ' + sess.views + '

') res.write('

expires in: ' + (sess.cookie.maxAge / 1000) + 's

') res.end() } else { sess.views = 1 res.end('welcome to the session demo. refresh!') } })

req.sessionID - 已载入Session的ID

通过req.sessionID属性,可以获取已加载的Session的ID。在Session创建/载入后,该属必是个只读值。


2.3.1 Session中的方法

Session.regenerate(callback) - 重新生成Session

调用本方法会重新生成Session。生成后,一个新的SID及session会被初始化到req.session,并且callback会被调用。

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

Session.destroy(callback) - 删除Session

删除Session并重置req.session属性,完成后,callback会被调用。

req.session.destroy(function(err) {
  // cannot access session here
})

Session.reload(callback) - 重新加载Session

从存储中重新加载Session,并重新填充req.session属性,完成后,callback会被调用。。

req.session.reload(function(err) {
  // session updated
})

Session.save(callback) - 保存Session到存储中

保存Session到存储中,用内存中的Session替换存储中的Session内容。

当Session发生改变时,会在响应完成后,自动调用本方法。

req.session.save(function(err) {
  // session saved
})

Session.touch() - 更新有效期

更新.maxAge属性,通常不需要调用本方法,因为Session中间件会自动调用。


2.3.2 Session中的属性

req.session.id - Session ID

每个Session都有个与之关联的唯一ID。本属性是req.sessionID的别名,所以也不能对其修改。

eq.session.cookie - 存储Session ID的Cookie对象

第个Session还会有一个与之对应的Cookie对象。

  • Cookie.maxAge - Cookie有效期

    req.session.cookie.maxAge会返回Cookie的剩余有效期,可以对其设置一个新值以调整.expire

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


2.4 Session存储

每个Session存储必须是一个EventEmitter并实现指定的方法。以下是一些必须实现、推荐实现和可选的方法:

store.all(callback) - 可选

以数组的形式返回存储中的所有Session。callback回调形式为:callback(error, sessions)

store.destroy(sid, callback) - 必须

通过指定的Session ID(sid)销毁/删除Session,callback回调形式为:callback(error)

store.clear(callback) - 可选

从存储中删除所有Session,callback回调形式为:callback(error)

store.length(callback) - 可选

用于获取存储的中Session数量,callback回调形式为:callback(error, len)

store.get(sid, callback) - 必须

通过指定的Session ID(sid)获取Session,callback回调形式为:callback(error, session)

store.set(sid, session, callback) - 必须

将指定的Session ID(sid)的值设置为sessioncallback回调形式为:callback(error)

store.touch(sid, session, callback) - 推荐

本推荐方法用于能过指定的Session Id和 session来"touch"指定的Sessoin,callback回调形式为:callback(error)

本方法主要用于存储将自动删除空闲Sessoin,该方法用于向存储发送信号指定会话处于活动状态,可能会重置空闲计时器。