HarmonyOS —— Remote Communication Kit 自定义缓存拦截器实战笔记
HarmonyOS —— Remote Communication Kit 自定义缓存拦截器实战笔记
前面你已经搞定了:
- HTTP 缓存基础能力
- Session 间缓存共享
- 各种过期策略
这一篇,就是 “我不想完全听 HTTP 协议的话,我要自己说了算” ——
自定义缓存拦截器(Custom Cache Interceptor)。
一、功能概览 & 设备支持
自定义缓存拦截器是干嘛的?
-
Remote Communication Kit 里已经有内置的 HTTP 缓存机制;
-
但有些业务的需求是这样的:
“我不完全想按 HTTP 标准缓存,我想:
- 只缓存某些方法(比如 PUT 也要缓存)
- 只按我自定义的 key 缓存
- 甚至无视响应头,完全自己管缓存写入/读取”
-
这时候就可以用 拦截器机制(
rcp.Interceptor)+ResponseCache自己写缓存逻辑。
版本 & 设备支持:
- 从 6.0.0(20) 开始支持自定义缓存拦截器;
- 支持设备:Phone / 2in1 / Tablet / Wearable / TV。
二、整体思路:拦截请求 → 查缓存 → 命中则返回,不命中则走网络再写入
自定义缓存拦截器的基本套路:
- 在
intercept(context, next)里:- 先根据
request构造一个 缓存 key(ResponseCacheKey); - 用这个 key 去
ResponseCache.get(key)查一下;
- 先根据
- 如果命中缓存:
- 不再往下走
next.handle(即不真正发网络请求); - 直接用
rcp.createResponse(...)包装缓存里的响应,返回给上层;
- 不再往下走
- 如果未命中:
- 调
next.handle(context)正常发网络请求; - 拿到
networkResponse后,用ResponseCache.set(key, createCachedResponse(...))写入缓存; - 最后把
networkResponse返回。
- 调
官方示例就干了一件事:写了一个 “盲缓存拦截器(BlindCacheInterceptor)” —— 不考虑 HTTP 协议里的 Cache-Control 等头,完全按自己定义的逻辑缓存。
三、BlindCacheInterceptor 示例拆解
1. 拦截器类结构
import { rcp } from '@kit.RemoteCommunicationKit';
class BlindCacheInterceptor implements rcp.Interceptor {
private readonly cache: rcp.ResponseCache;
constructor(cache: rcp.ResponseCache) {
this.cache = cache;
}
async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
const key: rcp.ResponseCacheKey = {
url: context.request.url,
method: context.request.method,
};
// 1. 先查缓存
const responseInCache = await this.cache.get(key);
if (responseInCache) {
// 直接用缓存里的数据构造 Response 返回
return rcp.createResponse(context.request, responseInCache.response, new Date());
}
// 2. 未命中 → 走真实网络请求
const networkResponse = await next.handle(context);
// 3. 写入缓存(序列化为 CachedResponse)
await this.cache.set(key, rcp.createCachedResponse(networkResponse));
// 4. 把真实响应返回给上层
return networkResponse;
}
}
逐段说一下这个逻辑:
(1) 构造缓存 key
const key: rcp.ResponseCacheKey = {
url: context.request.url,
method: context.request.method,
};
- Key 由两部分组成:
url:完整 URL(包含协议、host、path、query);method:HTTP 方法(GET / POST / PUT …)。
- 你也可以在以后 扩展自己的 key 策略(比如加上特定 header 值、tenantId 等),但示例里先用最基础的。
(2) 先查缓存:this.cache.get(key)
const responseInCache = await this.cache.get(key);
if (responseInCache) {
return rcp.createResponse(context.request, responseInCache.response, new Date());
}
cache.get(key)如果命中,就返回一个带response的结构;rcp.createResponse(request, cached.response, new Date()):- 用当前请求 + 缓存中的响应体,构造一个
rcp.Response; new Date()相当于“这次响应的时间戳”,便于上层逻辑统一处理。
- 用当前请求 + 缓存中的响应体,构造一个
这一段的要点:一旦命中缓存,就不会调
next.handle(context),因此不会真正触发网络请求。
(3) 未命中 → 发起网络请求并写入缓存
const networkResponse = await next.handle(context);
await this.cache.set(key, rcp.createCachedResponse(networkResponse));
return networkResponse;
next.handle(context)是标准拦截器链的“往下传”方式:- 后面可能还有别的拦截器;
- 最终会到实际的网络层;
rcp.createCachedResponse(networkResponse):- 把
Response包装成可缓存的结构(只保留适合存储的字段);
- 把
cache.set(key, cachedResponse):- 最终写入真正的缓存存储(内存 / 磁盘)。
这整个拦截器就是一个典型的 “Cache Aside” 模式:
先查缓存 → 命中就直接返回
不命中 → 去源头拿数据 → 再写回缓存
四、如何把自定义缓存拦截器接入 Session?
1. 创建 ResponseCache 实例
const responseCache = new rcp.ResponseCache({
persistent: {
kind: 'file-system',
pathToFolder: "/path/dir" // HTTP 缓存记录文件路径(沙箱目录)
}
});
- 路径和前面 HTTP 缓存章节的一样;
- 完全可以和 Session 间缓存共享那节配合起来使用。
2. 在 Session 中挂上拦截器
const session: rcp.Session = rcp.createSession({
interceptors: [new BlindCacheInterceptor(responseCache)]
});
- 和之前的
RequestUrlChangeInterceptor/ResponseHeaderRemoveInterceptor一样,缓存拦截器也是普通拦截器的一种; interceptors数组的顺序依然决定:- 请求时:执行顺序;
- 响应时:逆序回来的顺序。
五、请求流程:第一次命中网络,第二次命中缓存
1. 第一次请求:写缓存
const responseA = await session.put('https://www.example.com');
console.info(`Request succeeded, message is ${JSON.stringify(responseA)}`);
let cacheState = await responseCache.getState();
console.info(`The current number of cache entries is: ${cacheState.count}`);
几点小细节:
- 示例里故意用的是
PUT,而不是GET;- 正常 HTTP 缓存更多针对 GET;
- 这里证明:自定义缓存拦截器可以缓存你想缓存的任何方法(但业务上要自己保证一致性)。
getState().count:- 查看当前缓存条目数;
- 第一次成功后,理论上应为
1。
2. 第二次请求:命中拦截器的缓存逻辑
const responseB = await session.put('https://www.example.com');
console.info(`Request succeeded, message is ${JSON.stringify(responseB)}`);
cacheState = await responseCache.getState();
console.info(`The current cache hit count is: ${cacheState.hitCount}`);
- 因为 key = { url, method } 一样;
- 拦截器会先
cache.get(key),直接返回缓存; - 此时不会真正往网络发请求;
hitCount应当为1。
六、你可以怎么「魔改」这个缓存拦截器?
目前的 BlindCacheInterceptor 是最简单版本,它特点很明显:
- 忽略 HTTP 缓存头(Cache-Control, ETag, Expires 等);
- 忽略响应状态码;
- 只认 “同 URL + 同 Method”。
你在写博客 / 做题 / 实战时可以延展出一堆变体:
1. 只缓存 GET / 特定状态码
if (context.request.method !== 'GET') {
return next.handle(context);
}
const networkResponse = await next.handle(context);
if (networkResponse.statusCode === 200) {
await this.cache.set(key, rcp.createCachedResponse(networkResponse));
}
return networkResponse;
2. 按自定义 key 缓存(比如加上某个 Header)
const tenantId = context.request.headers?.['X-Tenant-Id'] ?? 'default';
const key: rcp.ResponseCacheKey = {
url: context.request.url,
method: context.request.method,
// 有些实现允许扩展字段,或者你在 path/query 里 encode
// 这里就当成你设计的“逻辑 key”
};
3. 与 Session 间缓存共享结合
- 拦截器里使用的
responseCache本身就可以:- 用“同一个实例”共享缓存;
- 或者用“同一路径 pathToFolder”共享磁盘缓存;
- 这样多个 Session 都能利用这套自定义的缓存规则。
4. 结合 TracingConfiguration 做“缓存命中率监控”
- 在
intercept里打印:- 命中/未命中日志;
- 利用
Tracing采样网络耗时,对比“命中缓存”和“走网络”的差异;
- 可直接作为“缓存优化前后”的数据对比基础。
七、考点速记版(给你之后写题 / 复习用)
-
功能:自定义缓存拦截器(基于
rcp.Interceptor+ResponseCache) -
版本:从 6.0.0(20) 开始支持
-
设备:Phone / 2in1 / Tablet / Wearable / TV
-
关键类 / 接口:
rcp.Interceptorrcp.RequestContextrcp.RequestHandlerrcp.ResponseCachercp.ResponseCacheKeyrcp.createCachedResponse(response)rcp.createResponse(request, cached.response, date)
-
典型流程:
async intercept(context, next) { const key = { url: context.request.url, method: context.request.method }; // 1. 先查缓存 const cached = await cache.get(key); if (cached) { return rcp.createResponse(context.request, cached.response, new Date()); } // 2. 未命中 → 发请求 const resp = await next.handle(context); // 3. 写缓存 await cache.set(key, rcp.createCachedResponse(resp)); return resp; } -
Session 接入方式:
const responseCache = new rcp.ResponseCache({ ... }); const session = rcp.createSession({ interceptors: [new BlindCacheInterceptor(responseCache)] });

浙公网安备 33010602011771号