在node项目开发过程中,缓存常常被用来解决高性能、高并发等问题。在我们的实际项目中,运用缓存的思路是内存缓存-->接口-->文件缓存。前面的总结中已经详细的说明了怎么实现和封装内存缓存和文件缓存。虽然二级缓存已经基本能够满足现在的所有场景需求,但现在我们再加一级redis缓存,从而使我们的项目更加稳定。
redis的封装:
const redis = require('redis');const myredis = { client:null, connect: function () { let RDS_PORT = 6379, //端口号 RDS_HOST = '94.191.**.**', //服务器IP RDS_PWD = '**********', //密码 RDS_OPTS = {}; //设置项 this.client = redis.createClient(RDS_PORT, RDS_HOST, RDS_OPTS); let c: any = this.client; c.auth(RDS_PWD, function () { console.log('通过认证'); }); c.on('error', function (err:any) { console.log('redisCache Error ' + err); }); c.on('ready', function () { console.log('redisCache connection succeed'); }); }, init: function () { this.connect(); // 创建连接 const instance:any = this.client; // 主要重写了一下三个方法。可以根据需要定义。 const get = instance.get; const set = instance.set; const setex = instance.setex; instance.set = function (key:any, value:any, callback:any) { if (value !== undefined) { set.call(instance, key, JSON.stringify(value), callback); } }; instance.get = function (key: any, callback: any) { return new Promise(function(resolve,reject){ get.call(instance, key, (err: any, val: any) => { resolve(JSON.parse(val)) }) }) }; instance.setex = function (key: any, value: any, callback: any) { if (value !== undefined) { setex.call(instance, key, 30*60*1000, JSON.stringify(value), callback); } }; return instance; },};export default myredis.init();
为了满足更多场景的使用,我们这里对redis的set和get方法进行了重写,并在结尾导出了新的redisclient实例 instance ,在get 方法中,为了在外部调用的过程中直接拿到数据,我们使用了 Promise 封装了一下get方法。
使用:
.............import rediscache from "../redis";.............async function apiCache(input_options: apicache_options): Promise<any> { ............ let key: string if (options.keystr != '') { key = encryption.sha1('apicache:' + options.keystr) } else if (options.postdata != null) { key = encryption.sha1('apicache:' + options.url + ';data:' + object_hash(options.postdata)) } else { key = encryption.sha1('apicache:' + options.url) //根据页面路径生成key } //redis缓存 let redis_cache = await rediscache.get(key); if (redis_cache != null){ return redis_cache; }; //内存缓存 let api_memery_cache = memorycache.get(key) if (api_memery_cache != null) { return api_memery_cache.body } else { //文件缓存 let api_file_cache = await filecache.get(key) //尝试文件缓存 // console.log(api_file_cache) if (api_file_cache != null) { // console.info('走文件') memorycache.put(key, api_file_cache) //写入内存 refreshCache(key, api_file_cache.time, options) return api_file_cache.body } } // console.info('直接调接口') try { let aoptions: any = { method: options.method, url: options.url, timeout: options.timeout, data: options.postdata, headers: options.headers } if (options.is_stream) { aoptions.responseType = 'arraybuffer' aoptions.responseEncoding = 'binary' } let back = await axios(aoptions) // console.log(back) let backdata = back.data; if (options.error_replace && options.check_callback) { if (options.check_callback(backdata)) { } else { logger.error({ 'error_message': '接口返回数据验证失败', 'url': options.url }) backdata = options.error_replace } } let cache_content = { time: Date.now(), body: backdata } rediscache.set(key, cache_content) memorycache.put(key, cache_content) filecache.put(key, cache_content) if (options.success_log) { logger.info({ url: options.url, back: backdata }) } return backdata } catch (error) { logger.error({ 'error_message': error.message, 'url': options.url }) if (options.error_replace !== undefined) { return options.error_replace } else { throw error } }}export default apiCache
完整的缓存中间件就不赘述,可看以前的总结web建站小结 ,在上面的删减版的代码中,为了方便观察,将redis缓存的读写放在了最上面,启动项目,在redis桌面管理工具(RedisDesktopManager)中查看:
页面上对应的部分: