Express中间件缓存

3

我正在尝试使用express中间件实现一些缓存,这似乎很好用,但是我在某处陷入了无限循环。

在我的路由器中,我有以下路由:

router.get('/test', [middleware.cache.cache('1 day', true), controllers.test]);

中间件middleware.cache.cache的结构如下所示:
module.exports.cache = function(time, global) {
    // Do some stuff with the time here

    return function cache(req, res, next) {
        // Keep a copy of the actual send method
        res._send = res.send;

        // Overwrite the res.send function
        res.send = function(obj) {
             console.log('[' + res.statusCode + '] Cache: ' + redisKey);

             // Get the key from redis
             redis.get(redisKey)
                .then(function(result) {
                    result = JSON.parse(result);

                    if(!_.isNull(result)) {
                        console.log('Expired cache found');

                        // Send initial object
                        return res._send(obj);
                    } else {
                        console.log('Cache found');

                        // Send back cached object
                        return res._send(result.obj);
                    }
                } else {
                    console.log('No data found');

                    storeInRedis(redisKey, obj, time);

                    // Send initial object
                    return res._send(obj);
                }
            })
            .fail(function(err) {
                console.log(err);

                return res._send(obj);
            });
        };

        next();
    };
};

我得到的输出结果如下所示:
[200] Cache: cache_global_test
Cache found
[200] Cache: cache_global_test
Cache found
...

我怀疑当我调用res._send(obj)时,它实际上是指我刚刚覆盖的原始res.send。这当然会导致无限循环。但我真的找不到任何解决方案。


请查看tamperexpress-interceptor - robertklep
1个回答

7

res._send = res.send 不会创建副本,它只是创建了一个到后面你要更改的函数的引用。

如果想要创建副本,请使用:https://www.npmjs.com/package/clone

为什么需要“覆盖 res.send 函数”呢?其实你可以在 redis.get(redisKey).then 中使用 next() 来达到你想要的目的。

我认为像这样更改 send 可能是危险的,因为它是内置的 express 方法,而你和其他开发人员期望它按照 express 文档中所描述的那样运行。

最好的方式可能是通过缓存中间件在 res 中添加 isCachedcache 属性,然后在“最后一个函数”中根据缓存值和缓存中间件的存在情况进行相应的处理,从而明确地知道是否存在缓存值。


redis.get().then中使用next()将仅继续中间件链,这不是我想要的,因为最后一个函数是控制器,将从数据库检索项目,这就是为什么我要插入中间件的原因。 - woutr_be
我认为像这样更改 send 可能是一件危险的事情,因为它是一个内置的 express 方法,而你的“最后一个函数”依赖于它才能正常工作。最好在中间件中添加 isCachedcache 属性到 res 中,然后在“最后一个函数”中根据情况进行操作,使其明确知道可能存在缓存值和缓存中间件。 - krl
这是真的,但也意味着在每个路由回调中添加大量自定义代码。 - woutr_be
3
我想评论一下这个答案有多重要。它帮我们节省了数小时的调试时间。我甚至在博客中链接了它:https://medium.com/the-node-js-collection/simple-server-side-cache-for-express-js-with-node-js-45ff296ca0f0 - Flame_Phoenix
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接