Nodejs Express session 模块的扩展

Nodejs Express session 模块的扩展

session 数据的处理是很敏感的,在每个请求的处理逻辑块中直接调用 req.session 显得很不规范,所以需要一个模块来单独管理session的读写。

再考虑不能为每个用户的session添加读写function,因为这样会导致性能损耗,所以必须对session对象做一个基类扩展。

在无法显式知道session 构造函数的情况下只能使用 constructor 关键字,进而获取其 prototype 属性,实现原型继承。

session.js

var sessionConstructed = false;

exports.get = function (req) { var session = req.session;

if (!sessionConstructed) { var cst = session.constructor;

cst.prototype.userInfo = function () {
    return this.user;
};
cst.prototype.initUser = function (username, source) {
    this.user = {
        username: username,
        source: source
    };
};
cst.prototype.clearUser = function () {
    this.user = null;
};

cst.prototype.checkVerifyCode = function (code) {
    if (!this._verifyCode || this._verifyCode != code.toLowerCase()) {
        this._verifyCode = null;
        return false
    } else {
        return true;
    }
}
cst.prototype.setVerifyCode = function (code) {
    this._verifyCode = code.toLowerCase();
}
sessionConstructed = true;

}

return session; }

howToUse.js

var session = require('./session.js')

function onSomeRequst(req, res){

var ses = session.get(req);

var userInfo = session.get(req).userInfo();

var verifyCode = '1234';

var isVerifyCodeRight = session.checkVerifyCode(verifyCode);
}

2 回复

Nodejs Express Session 模块的扩展

在Web应用开发中,Session数据的处理是非常重要的。为了保持代码的整洁和可维护性,通常不建议在每个请求处理逻辑中直接操作req.session。因此,我们需要一个模块来专门管理Session的读写。

此外,我们还需要确保不会为每个用户的Session对象添加特定的方法,因为这会带来不必要的性能开销。所以,我们可以通过扩展Session对象的原型来实现这一目标。

由于我们无法显式地知道Session构造函数的具体实现细节,我们可以利用constructor关键字来获取Session对象的原型,并通过原型继承的方式添加通用方法。

session.js

var sessionConstructed = false;

exports.get = function (req) {
    var session = req.session;

    if (!sessionConstructed) {
        var cst = session.constructor;

        // 添加用户信息方法
        cst.prototype.userInfo = function () {
            return this.user;
        };

        // 初始化用户信息
        cst.prototype.initUser = function (username, source) {
            this.user = {
                username: username,
                source: source
            };
        };

        // 清除用户信息
        cst.prototype.clearUser = function () {
            this.user = null;
        };

        // 验证验证码
        cst.prototype.checkVerifyCode = function (code) {
            if (!this._verifyCode || this._verifyCode !== code.toLowerCase()) {
                this._verifyCode = null;
                return false;
            } else {
                return true;
            }
        };

        // 设置验证码
        cst.prototype.setVerifyCode = function (code) {
            this._verifyCode = code.toLowerCase();
        };

        sessionConstructed = true;
    }

    return session;
};

howToUse.js

var session = require('./session.js');

function onSomeRequest(req, res) {
    var ses = session.get(req);

    // 获取用户信息
    var userInfo = ses.userInfo();

    // 设置验证码
    ses.setVerifyCode('1234');

    // 验证验证码
    var isVerifyCodeRight = ses.checkVerifyCode('1234');
}

解释

  • session.js 文件中的 exports.get 函数用于获取当前请求的Session对象,并在首次调用时初始化一些常用方法。

  • cst.prototype 中定义了几个方法:

    • userInfo():返回当前用户的用户名等信息。
    • initUser(username, source):初始化用户信息。
    • clearUser():清除用户信息。
    • checkVerifyCode(code):验证验证码是否正确。
    • setVerifyCode(code):设置验证码。
  • howToUse.js 文件中的 onSomeRequest 函数展示了如何使用这些方法。通过调用 session.get(req) 获取当前请求的Session对象,并调用相应的方法进行操作。

这种方式使得Session的管理更加模块化和易于维护。


从提供的内容来看,session.js 文件中的代码试图通过修改 req.session.constructor.prototype 来扩展会话功能。这种做法虽然实现了目的,但并不推荐,因为它可能会影响到所有使用该会话中间件的会话实例,并且可能与其他中间件或库产生冲突。

更推荐的做法是创建一个新的模块,将自定义的会话操作封装在一个类中。这样可以更好地控制会话数据的访问,并避免影响全局的会话对象。

以下是改进后的示例:

sessionManager.js

class SessionManager {
    constructor(session) {
        this.session = session;
    }

    getUserInfo() {
        return this.session.user;
    }

    initUser(username, source) {
        this.session.user = {
            username: username,
            source: source
        };
    }

    clearUser() {
        this.session.user = null;
    }

    checkVerifyCode(code) {
        if (!this.session._verifyCode || this.session._verifyCode !== code.toLowerCase()) {
            this.session._verifyCode = null;
            return false;
        } else {
            return true;
        }
    }

    setVerifyCode(code) {
        this.session._verifyCode = code.toLowerCase();
    }
}

module.exports = SessionManager;

howToUse.js

const SessionManager = require('./sessionManager');

function onSomeRequest(req, res) {
    const sessionManager = new SessionManager(req.session);

    const userInfo = sessionManager.getUserInfo();

    const verifyCode = '1234';
    const isVerifyCodeRight = sessionManager.checkVerifyCode(verifyCode);
    
    // 其他逻辑...
}

这种方式不仅提高了代码的可维护性和可读性,还避免了直接修改全局会话构造函数带来的潜在问题。

回到顶部