腾讯云授权服务中心
五万用户的选择,您身边的云计算顾问
发布日:2022-02-04 20:39 阅读数:
import { Context, Next } from 'koa'; // 默认的 cache key 计算规则:直接取 query string const defaultCacheKeyFn = <T extends Context>(ctx: T) => ctx.querystring; // 默认的缓存获取策略 const defaultGetCacheFn = async <T extends Context> (cacheKey: string, ctx: T, next: Next) => { // 根据 cache key 获取 cache value // getWithCache: 封装本地和 redis 缓存获取 const cacheVal = await getWithCache(cacheKey); // 缓存优先,缓存命中触发异步更新 if (cacheVal) { // 异步执行 next 获取新鲜的 值 next().then(() => { // 通过 ctx.body 获取新值,更新到缓存 setWithCache(cacheKey, JSON.stringify(ctx.body)); }); ctx.body = JSON.parse(cacheVal); return; } // 没有缓存,直接执行 await next(); // 新建缓存 setWithCache(cacheKey, JSON.stringify(ctx.body)); }; // 获取缓存中间件 export const getCacheMiddleware = <T extends Context>(cacheKeyFn = defaultCacheKeyFn, getCacheFn = defaultGetCacheFn) => async (ctx: T, next: Next) => { try { // 为这次请求计算一个 cache key const cacheKey = cacheKeyFn<T>(ctx); // 封装缓存策略 await getCacheFn<T>(cacheKey, ctx, next); } catch (e) { console.error('缓存中间件出错', e); throw e; // 不能降级,有可能 next 已经执行了 // await next(); } };
看看刚刚发生了什么。
const localCacheExp = 10 * 60; // 10min // 获取缓存值:先本地,后 redis export const getWithCache = async (key: string) => { // 先计算一个内部 key const localCacheKey = `_redis_key_${key}`; // 本地缓存如果有,直接返回 if (defaultLocalCache.exists(localCacheKey)) return defaultLocalCache.get(localCacheKey); // 否则,到 redis 里取 // redis 里不管存在与否,都作为最终结果返回 const result = await defaultRedisClient.get(key); if (result) defaultLocalCache.setex(localCacheKey, localCacheExp, result); return result; }; // 设置缓存值,先 redis,后本地 export const setWithCache = async (key: string, value: string | number) => { // 30min 失效 await defaultRedisClient.setex(key, 30 * 60, value); const localCacheKey = `_redis_key_${key}`; defaultLocalCache.setex(localCacheKey, localCacheExp, value); };
下面看看 defaultLocalCache,如何实现类 redis 的接口,并具备缓存失效机制。
// 本地缓存类 export class LocalCache { private cache: Record<string, any> constructor() { this.cache = {}; } // 类似 redis setex setex(key: string, seconds: number, value: any) { this.cache[key] = value; // 缓存定时失效 setTimeout(() => { delete this.cache[key]; }, seconds * 1000); } get(key: string) { return this.cache[key]; } exists(key: string) { return Object.prototype.hasOwnProperty.call(this.cache, key); } } // 使用单例 plain object export const defaultLocalCache = new LocalCache();
前面三步,已经实现了缓存中间件,最后一步,看看怎么使用。
import Router from 'koa-router'; // 使用默认的 cache key 计算以及缓存策略 const cacheMiddleware = getCacheMiddleware(); export const router = new Router(); // 在特定 API 应用 router.get('/article/detail', cacheMiddleware, detailController);
编辑:航网科技 来源:腾讯云
本文版权归原作者所有 转载请注明出处
Copyright © 2011-2020 www.hangw.com. All Rights Reserved 深圳航网科技有限公司 版权所有 增值电信业务经营许可证:粤B2-20201122 - 粤ICP备14085080号
微信扫一扫咨询客服
全国免费服务热线
0755-36300002