是否可以在创建后将 Express Session 更改为不同的商店

Posted

技术标签:

【中文标题】是否可以在创建后将 Express Session 更改为不同的商店【英文标题】:Is it possible to change the Express Session to a different store after creation 【发布时间】:2018-12-14 13:07:18 【问题描述】:

我使用 memcached 作为 ExpressJS 会话的后备存储 - 通过应用配置设置选择。如果无法联系到 memcached 主机,我想从 memcached 退回到内存。 (这不一定是生产策略,因为 memcached 非常可靠 - 当我忘记在 dev 中启动 Docker 实例时,它更适用,但仍然可能是生产故障安全的。)

我首先认为我可以“app.use”一个新的会话实例,并尝试删除第一个,但我已经读到很难(如果可能的话)“不使用” Express 中间件,即交换中间件在链中就地,或者通常在设置链后对其进行修补。

连接超时后的问题是,应用中间件已经设置好,在会话中间件之后安装了许多进一步的服务。

我的第二个想法是我可以重新配置 Express Session 实例本身并在它创建后更改存储吗?我在the documentation 中看不到任何方法。

我的第三个想法是将 express-session 包装在一个新的“可交换存储”类中,但我对包装整个界面的范围持谨慎态度。

例如在我的应用设置中:

app.use(services.session.middleware());

// then a lot of other middleware...
app.use(bodyParser.json());
app.use(bodyParser.urlencoded(extended: false));
app.use(cookieParser());
app.use(express.static(path.join(rootPath, 'public')));
...etc

在会话服务中,它选择和配置会话实例:

function middleware() 
    // default / Memory Store options
    const opts = 
        resave: false,
        saveUninitialized: false,
        ...etc
        
    ;

    // Install any configured backing store
    if(config.session.storage === "memcached")
        const MemcachedStore = require('connect-memcached')(session);
        opts.proxy = 'true';
        opts.store = new MemcachedStore(
            hosts: ...,
            secret: ... 

        );
        const errorHandler = (type, details)=> 
            /* HERE I WOULD LIKE TO RE-MAKE THE SESSION USING MEMORY
             * AND DISCARD THE MEMCACHED ONE
             * (THIS HAPPENS AFTER APP BOOT HAS FINISHED)
            */
            console.error( String.format("Memcached 3 with host:0 details:1.", details.server, details.messages.join( '' ), type)); 
        
        opts.store.client.on('failure', details => errorHandler('failure', details));
        opts.store.client.on('issue', details => errorHandler('issue', details));
    

    return session(opts);

【问题讨论】:

【参考方案1】:

我认为您可以尝试多种方法。第一种是根据您在启动时提供的配置(可能通过 config 或 nconf 之类的模块)来配置存储系统。第二个是在启动应用程序时运行快速检查,以确保它可以访问 memcache 服务,如果它不能则回退到内存并出现错误。

我会厌倦做这些,因为你使用的是 docker,而且它应该很容易启动 memcache。这是因为如果出现连接问题,您将引入可能在生产中触发的代码,然后您可能会发现自己意外地服务于内存不足的会话,而不是可能没有意识到的 memcache 之类的东西。

我将在这里扩展这两种策略,并提供第三种可能更好的选择。

1.根据配置选择缓存系统

这应该相当简单,只需将您的配置提取到某种配置管理器/环境变量(检查配置或 nconf)中。启动应用程序并连接会话中间件时,您可以提取所有可能的配置,查看哪些存在并基于此附加一个。这类似于您的if (config.session.storage === 'memcache") 目前的外观。只需使用不配置的回退,快速会话中间件将回退到内存中。这样您就可以完全省去配置,而始终使用内存进行开发。

2。在连接到所需服务之前运行测试

结合上述内容,如果提供了 memcache 详细信息,您可以通过在启动时尝试在 memcache 中存储一些内容来运行快速测试。也许new Date(); 在应用程序启动时发出信号?如果这引发错误,那么不要将MemcachedStore 附加到 express-session 选项中,您可以安全地销毁 MemcachedStore。

3.如果无法连接到 Memcached 则抛出错误

这与#2 进一步结合。如果您确定提供了 memcache 配置,那么我会亲自检查您是否可以联系服务,如果不能,则抛出错误并停止应用程序。这意味着在开发中您会立即知道问题所在,在生产中您也可以根据应用程序无法启动的事实为自己触发自动警报。

这可能是最好和最强大的解决方案,通常在谈论连接服务时进行静默回退并不是一个好主意,因为事情可能会出错而您不知道。我明白这是出于开发目的,您需要务实,但如果它可以避免您意外地从服务器内存中提供所有会话,那么这将是非常有益的。

【讨论】:

好的,是的,你回避这个问题是对的!我实际上已经在做 1)我的配置已经具有基于 env 的覆盖,并且我可以轻松地为“dev”环境重新选择内存存储。我可以做到这一点,然后对交换会话策略的复杂性的需求就消失了。但是...我最近在另一个 SO 中阅读了有关此主题的有趣建议,即不要在 dev 和 prod 中运行不同的服务,因为您没有测试所有内容。所以我想继续在 dev 中使用 memcached 并体验任何怪癖。 我认为 2) 和 3) 是最合适的。在开发中 - 只是抛出一个错误说“嘿,你又忘记了 docker doofus?”。但在生产中 - 已经有针对这个问题的成熟方法 - 即 memcached 已经有一个网格/网格概念并尝试重新/连接到各种服务器。我想我不应该尝试复制或重新解决那些久经考验的技术。 我想说更大的问题是,如果你不小心爆出你的配置,推送代码,突然你的软件甚至没有尝试连接到 memache。在那种情况下,您可能永远不会知道,直到您开始获得“99% 警报的服务器内存”(取决于应用程序的大小)。我认为可以在启动应用程序的其余部分之前添加一个额外的 ping memcache 并检查它是否可以实际与服务通信,这是一个非常标准的前期安全检查。

以上是关于是否可以在创建后将 Express Session 更改为不同的商店的主要内容,如果未能解决你的问题,请参考以下文章

node.js中express-session配置项详解

从 Jade 模板访问 Express.js 请求或会话

使用 nodejs/express 登录后将用户重定向到 Angular 应用程序

node.js中express-session配置项详解

使用 Passport.js、express-session 和 express-mysql-session 进行用户身份验证

express-session 在设置 cookie 时会导致服务器崩溃?