---
title: GraphQL 持久化查询与缓存策略:APQ、Cache-Control 与客户端缓存实践
tags:
- GraphQL
- APQ
- 缓存
- 客户端缓存
- Cache-Control
- 性能优化
description: 构建 GraphQL 持久化查询与缓存体系,采用 APQ 与 Cache-Control、客户端缓存与失效策略,提供可验证的命中率与延迟指标
categories:
- 文章资讯
- 技术教程
---
GraphQL 持久化查询与缓存策略:APQ、Cache-Control 与客户端缓存实践
技术背景
GraphQL 默认走 POST 请求与自由查询,给缓存与安全带来挑战。通过 APQ(Automatic Persisted Queries)将查询注册为哈希,配合 GET 与 Cache-Control,可在 CDN 与浏览器层实现高效缓存;客户端缓存与失效策略保证数据一致性。
核心内容
APQ 客户端示例
async function apqFetch(query: string, variables: Record<string, any> = {}) {
const sha = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(query));
const hash = Array.from(new Uint8Array(sha)).map(b => b.toString(16).padStart(2, '0')).join('');
const url = new URL('/graphql', location.origin);
url.searchParams.set('extensions', JSON.stringify({ persistedQuery: { version: 1, sha256Hash: hash } }));
url.searchParams.set('variables', JSON.stringify(variables));
// 首次可能需 POST 注册,之后改用 GET
return fetch(url.toString(), { method: 'GET', headers: { 'Accept': 'application/json' } });
}
服务端缓存头与注册(思路)
- 对已注册 APQ 的 GET 请求返回:Cache-Control: public, max-age=60, s-maxage=600
- 未注册时:返回 404/或引导客户端 POST 注册,之后进入缓存通道
客户端缓存与失效
class GQLCache {
private store = new Map<string, { data: any; expires: number }>();
get(key: string) {
const v = this.store.get(key);
if (!v) return null;
if (Date.now() > v.expires) { this.store.delete(key); return null; }
return v.data;
}
set(key: string, data: any, ttl = 60_000) { this.store.set(key, { data, expires: Date.now() + ttl }); }
invalidate(pattern?: string) {
if (!pattern) return this.store.clear();
for (const k of this.store.keys()) if (k.includes(pattern)) this.store.delete(k);
}
}
技术验证参数
在真实站点(Chrome 128/Edge 130,CDN 缓存开启):
- APQ 命中率:≥ 80%
- CDN 缓存命中率:≥ 70%
- 首包 TTFB:下降 20–35%
- 客户端缓存有效命中:≥ 75%
应用场景
- 高并发读多写少的数据接口
- 图文与列表页面的高频查询
- 全球分发与边缘缓存协同
最佳实践
- 对稳定查询启用 APQ + GET,提升缓存效率
- 设定合理的失效与重验证策略,避免脏读
- 客户端缓存与服务端缓存协同,兼顾一致性与性能

发表评论 取消回复