session 的一些问题

  1. 无法共享,因为所有网站不可能共用一台服务器,可能会有多个
  2. 不安全,如果服务器崩溃,数据也会丢失
  3. 性能低,普通的session文件都是存放本地,io非常慢(相对)

于是就有两中方式进行优化:

  1. 丢数据库mysql
  2. 丢redis中

mysql

koa作者提供了一个接口store,这个接口也是在session的配置对象里的,他是一个对象,里面有三个生命周期函数,我称之为生命周期函数。

他们会在session操作完后触发。

server.use(session({
    maxAge: 20 * 60 * 1000,
    renew: true,
    store: {
        get(key, maxAge) { //获取

        },
        set(key, session, maxAge) { //设置

        },
        destroy(key) { //删除

        }
    }
}, server));

get是获取,session要从mysql获取的话,通过这个函数返回给koa数据。所有需要一个key,一个过期时间做判断

set是设置,设置的话,key是必须的,然后就是session对象本身的值了,还有就是过期时间

destroy是删除,删除的话有key就行了。

数据库创建

我们需要创建一个数据库session,数据库里面要有一个表,用于存储session信息的,命名为user_session

表里面有几个字段:

  1. ID 唯一,主键,int类型(int只有11位),不能为null,自增
  2. sessID,唯一,主键,varchar类型(80长度),不能为null,存放key
  3. view int类型,这个是我们自制的属性,用于存放浏览次数
  4. expires int类型,用于存放过期时间,必须为秒,因为int只有11位

四个字段创建好后,我们就可以连接这个数据了

const mysql = require("promise-mysql");

(async () => {
    const sessionDB = await mysql.createPool({
        host: "localhost",
        user: "root",
        pass: "123456",
        database: "session"
    });
})();

由于使用了promise-mysql,他的方法是一个异步的,所以做一个自运行函数,async开头

然后我们就可以先写get方法:

async  get(key, maxAge) { //获取
    const data = await sessionDB.query("SELECT* FROM user_session WHERE sessID=?", [key]);

    if (data.length) { //存在
        if (data.expires * 1000 < Date.now() + maxAge) { //过期
            return {};
        } else { //没过期
            return {
                view: data[0]["view"]
            };
        }
    } else { //不存在
        return {};
    }
},

get是获取,从mysql里面拿数据,于是使用了SELETE 搜索所有user_session表里面,sessID要等于key的数据。

他会返回一个数组,所有的数据库操作都会返回一个数组,我们判断这个数组的length,判断是否有值。

没有就表示这是一个新用户,我们返回一个空对象,有的话,就判断时间有没有过期。

mysql里面存储的时间必须是秒,而且必须是正确的年月日那种秒,你不可能存个20秒,谁知道你这个20秒是哪段时间的,所以数据库的时间必须是当前时间+过期时间

所以我们乘以1000转换成秒,然后判断和当前时间的大小,如果小于,那就过期了,那就返回一个空对象。

如果没有过期,那就返回一个session里面存储的数据对象,像id,哪些肯定是不返回的,因为我们自制的只有一个view。

set方法:

async  set(key, session, maxAge) { //设置
    const isKey = await sessionDB.query("SELECT* FROM user_session WHERE sessID=?", [key]);
    const expires = Math.floor((Date.now() + maxAge) / 1000);

    if (isKey.length) { //已存在,进行更新数据
        await sessionDB.query("UPDATE user_session SET view=?,expires=? WHERE sessID=?", [session.view, expires, key]);
    } else { //不存在,直接添加
        await sessionDB.query("INSERT INTO user_session (sessID,view,expores) VALUES(?,?,?)", [key, session.view, expires]);
    }
},

设置的话需要判断下有没有存在这个key,如果存在是更新,不存在是直接添加。

由于数据库的时间是秒,所我们用当前时间+过期时间,除以1000转成秒,然后去除浮点数,得到存入数据的时间。

然后就是设置数据库的内容了。

删除

async destroy(key) { //删除
    await sessionDB.query("DELETE FROM user_session WHERE sessID=?", [key]);
}

定时清理session

session是一个和浏览器建立连接后的一个临时存储,如果用户超时未连接的话,session就会失效了。

但是由于我们使用的是mysql存储,所有实际上弃用的session还存储在我们的mysql里面,我们需要及时清理掉

//定时清理 10分钟
setInterval(async () => {
    await sessionDB.query("DELETE FROM user_session WHERE expires<?", [Math.floor(Date.now() / 1000)])
}, 10 * 60 * 1000)

创建一个无限定时器吗,十分钟运行一次,然后判断表里面时间小于当前时间的,直接删除。

分类: Node 标签: nodekoasession

评论

暂无评论数据

暂无评论数据

目录