服务器端缓存
使用基于 Apollo Server 的子图配置服务器端缓存
ⓘ 注意
使用缓存控制与Apollo Federation一起使用至少需要 v3.0.2 版本的 Apollo Server 在您的 子图和网关中。Apollo Server 的缓存提示 API 自 v3 版本起已有所演变,因此请务必查看 更新的缓存文档。
使用子图缓存提示
为了在使用 Apollo Server 的子图中设置 静态缓存提示,必须在子图模式中包括@cacheControl
指令和 CacheControlScope
枚举定义:
enum CacheControlScope {PUBLICPRIVATE}directive @cacheControl(maxAge: Intscope: CacheControlScopeinheritMaxAge: Boolean) on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
子图计算并设置发送给网关的响应的缓存提示,然后网关计算整体响应的缓存提示。这个提示基于子图执行的查询计划中所有响应的最严格的设置。
缓存提示也可以在子图解析器中动态设置。
设置实体缓存提示
子图模式定义了Query 类型的_entities 根字段,所以所有需要实体 解析的查询计划都有一个默认设置为0的maxAge。要覆盖此默认行为,您可以在实体 定义中添加一个@cacheControl 指令:
type Book @key(fields: "isbn") @cacheControl(maxAge: 30) {isbn: String!title: String}
当_entities 字段被解析时,它会检查具体的缓存提示类型(例如上面示例中的Book 类型)并应用该提示。
要动态设置缓存提示,cacheControl 对象及其方法也将在__resolveReference 解析器的info 参数中可用。
在网关中覆盖子图缓存提示
如果一个子图没有指定max-age,网关将假设其响应(以及随之而来的整体响应)不能被缓存。要覆盖此行为,您可以在RemoteGraphQLDataSource 的didReceiveResponse 方法中设置cache-control 标头。
此外,如果网关应该忽略来自将影响操作缓存策略的子图的cache-control 响应标头,则可以将RemoteGraphQLDataSource 的honorSubgraphCacheControlHeader 属性设置为false(默认值为true)。
将 honorSubgraphCacheControlHeader
设置为 false
对应的响应缓存能力两边都没有影响。换句话说,此属性不会决定响应是否可以缓存,但它会将 子图's cache-control
}}
以下有一些详细示例,说明了覆盖一个 子图 的此报头会产生的行为。
示例 maxAge
计算
多子图实体
考虑以下 子图模式:
type Astronaut @key(fields: "id") @cacheControl(maxAge: 20) {id: ID!name: String}type Query {astronaut(id: ID!): Astronautastronauts: [Astronaut]}
type Mission {id: ID!crew: [Astronaut]designation: String!startDate: StringendDate: String}type Astronaut @key(fields: "id") {id: ID!missions: [Mission]}type Query {mission(id: ID!): Mission @cacheControl(maxAge: 10)missions: [Mission]}
对于以下 查询:
query GetMissionWithCrew {mission(id: 1) {designationcrew {name}}}
将把响应考虑为不可缓存。
宇航员子图的响应中的 cache-control
}头将是应用程序的 max-age=20, public
,这是基于应用在 “Astronaut” 类型上的缓存提示,
任务子图,不过,不包括将其响应发送到网关的 cache-control
}头,因此表明它是不可缓存的。因此,发送到客户端的整个响应都是不可缓存的。乍一看,这种表现可能出乎意料,因为应用在 mission
Root 查询字段上有一个 @cacheControl(maxAge: 10)
指令。但仔细检查后,我们发现该字段返回了包含非标量 Astronaut 字段的 Mission
类型,并且此类型将应用默认的 默认 maxAge} 为 0
。
任务子图不清楚宇航员子图中在 Astronaut
类型上设置的缓存提示,因此有两种方法可以解决这个问题。 第一种选择是
type Mission {id: ID!crew: [Astronaut] @cacheControl(inheritMaxAge: true)designation: String!startDate: StringendDate: String}
将此参数设置为 true
,将 @cacheControl
指令应用于任务子图中的 Astronaut
实体:
第二种选择是将 @cacheControl
指令的 maxAge
值设置到 Astronaut 实体上,代替以下选项:
type Astronaut @key(fields: "id") @cacheControl(maxAge: 20) {id: ID!missions: [Mission]}
在 missions 子图中为 Astronaut 类型设置 maxAge
属性,引发了一个重要的考虑:是否应该明确为它们所包含的任何实体类型设置这些值。在大多数情况下,最好在与实体类型用作返回类型的地方应用 @cacheControl(inheritMaxAge: true)
,以避免歧义。根据您的需求,您可能希望通过为子图应用自定义 linting 完全禁止此设置,以确保多个子图不要设置 maxAge
或 scope
参数。在应用 @cacheControl
指令时。
网关覆盖
对于这些 子图模式:
type Astronaut @key(fields: "id") @cacheControl(maxAge: 20) {id: ID!name: String}type Query {astronaut(id: ID!): Astronautastronauts: [Astronaut]}
type Mission {id: ID!crew: [Astronaut] @cacheControl(inheritMaxAge: true)designation: String!startDate: StringendDate: String}type Astronaut @key(fields: "id") {id: ID!missions: [Mission]}type Query {mission(id: ID!): Mission @cacheControl(maxAge: 10)missions: [Mission]}
以及这个 操作:
query GetMissionWithCrew {mission(id: 1) {designationcrew {name}}}
预期的响应将具有 cache-control
标头值 max-age=10, public
。
然而,如果您想忽略 missions 子图提供的 cache-control
标头,可以通过将 RemoteGraphQLDataSource 选项中的 honorSubgraphCacheControlHeader
设置为 false
对该子图进行设置:
const gateway = new ApolloGateway({// ...buildService({ name, url }) {return new RemoteGraphQLDataSource({url,honorSubgraphCacheControlHeader: name === "missions" ? false : true;});}});
现在响应将具有 cache-control
标头值 max-age=20, public
,因为在网关计算整体标头时,只考虑了 astronauts 子图的缓存提示。
或者,我们可以替代 missions 子图响应中的 max-age=10, public
标头,并将其设置为完全不同的值,如下所示:
const gateway = new ApolloGateway({// ...buildService({ name, url }) {return new RemoteGraphQLDataSource({url,didReceiveResponse({ response }) {if (name === "missions") {response.http.headers.set("cache-control","max-age=5, public");}return response;}});}});
整体响应现在将具有 cache-control
标头值 max-age=5, public
,因为 missions 子图覆盖的标头比 astronauts 子图提供的 max-age=20, public
标头更为严格。