加入我们,于10月8日至10日在纽约市学习最新关于GraphQL联邦和API平台工程的技巧、趋势和新闻。加入我们,参加2024年纽约市的GraphQL峰会
文档
免费开始

自动持久查询

通过发送较小的请求提高网络性能


客户端请求将包含要执行的 字符串的HTTP请求发送到 。根据您图的模式,有效的查询字符串的大小可能是任意大的。随着查询字符串变得更大,显著的延迟和网络使用可能会导致客户端性能的明显下降。

为了提高大 查询字符串 的网络性能, Apollo Server 支持 自动持久查询 (APQ)。持久查询是一个查询字符串,它在服务器端进行缓存,包括其唯一标识符(总是其SHA-256哈希)。客户端可以发送该标识符而不是对应的查询字符串,从而大大减少请求数据的大小(响应大小不受影响)。

为了持久化查询字符串,Apollo Server必须首先从请求客户端接收它。结果,每个唯一的查询字符串至少必须发送到Apollo Server一次。一旦任何客户端发送一个查询字符串进行持久化,每个执行该查询的客户端都可以从中受益。

Apollo ServerClient appApollo ServerClient appFails to find persisted query stringPersists query string and hashTime passesFinds persisted query stringSends SHA-256 hash of query string to executeResponds with errorSends both query string AND hashExecutes query and returns resultSends SHA-256 hash of query string to executeExecutes query and returns result

在客户端发送查询作为GET请求时特别有效。这使得客户端可以利用浏览器缓存并与CDN集成

因为查询标识符是确定的散列,客户端可以在运行时生成它们。不需要额外的构建步骤。

Apollo客户端设置

Apollo Server支持APQ而不需要任何额外的配置。然而,一些客户端侧配置是必需的。

为了在中设置APQ,首先在初始化ApolloClient的同一文件中导入

index.ts
import { createPersistedQueryLink } from '@apollo/client/link/persisted-queries';

这个函数创建了一个可以添加到您的客户端链中的链接Apollo链。该链负责生成APQ标识符,使用[hashed]查询的GET请求,并在必要时重试带有查询字符串的请求。

在终止链接之前,将持久化查询链接添加到链中的任何位置。以下示例显示了基本的两个链接链:

import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
import { createPersistedQueryLink } from '@apollo/client/link/persisted-queries';
import { sha256 } from 'crypto-hash';
const linkChain = createPersistedQueryLink({ sha256 }).concat(
new HttpLink({ uri: 'https://127.0.0.1:4000/graphql' }),
);
const client = new ApolloClient({
cache: new InMemoryCache(),
link: linkChain,
});

命令行测试

您可以直接从命令行测试APQ。本节还帮助说明了APQ请求的形状,因此您可以将其用于除Apollo客户端之外的其他GraphQL客户端中添加对APQ的支持。

本节假设您的服务器在本地运行, https://127.0.0.1:4000/graphql

每个都支持以下查询(该查询请求Query类型中的__typename字段):

{
__typename
}

此查询字符串的SHA-256哈希如下:

ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38
  1. 通过在curl命令中提供其哈希值,尝试在你的运行服务器上执行此查询,如下所示:

    curl --get https://127.0.0.1:4000/graphql \
    --header 'content-type: application/json' \
    --data-urlencode 'extensions={"persistedQuery":{"version":1,"sha256Hash":"ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"}}'

    第一次尝试时,Apollo Server会以包含代码PERSISTED_QUERY_NOT_FOUND的错误响应。这告诉我们Apollo Server尚未收到相关的查询字符串。

  2. 发送包含查询字符串及其哈希值的后继请求,如下所示:

    curl --get https://127.0.0.1:4000/graphql \
    --header 'content-type: application/json' \
    --data-urlencode 'query={__typename}' \
    --data-urlencode 'extensions={"persistedQuery":{"version":1,"sha256Hash":"ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"}}'

    这一次,服务器持久化了查询字符串,并按预期响应查询结果。

    您提供的哈希值必须是查询字符串的确切SHA-256哈希值。如果不是,Apollo Server将返回错误。

  3. 最后,再次尝试步骤1的请求

    curl --get https://127.0.0.1:4000/graphql \
    --header 'content-type: application/json' \
    --data-urlencode 'extensions={"persistedQuery":{"version":1,"sha256Hash":"ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"}}'

    这一次,服务器响应查询结果,因为它在其缓存中成功定位了相关的查询字符串。

GET请求与CDN上APQ的使用

APQ的绝佳应用是运行Apollo Server在CDN后面。许多CDN只缓存GET请求,但许多GraphQL查询过长而不能舒适地放在可缓存的GET请求中。当使用createPersistedQueryLink({useGETForHashedQueries: true})创建APQ链接时,Apollo Client会自动以GET请求形式发送短哈希查询,使CDN能够提供这些请求。对于完整长度的查询和所有mutations,Apollo Client将继续使用POST请求。

CDN集成

内容分发网络(CDN)fly.ioCloudflareAkamai以及Fastly都能够在客户端附近缓存内容,从附近的服务器以低延迟传输数据。Apollo Server使得使用CDN与GraphQL查询缓存完整响应同时执行更动态的查询变得简单。

Apollo Server与内容分发网络(CDN)配合良好,用于缓存完整的GraphQL查询结果。通过添加适当的缓存提示,Apollo Server可以计算CDN可以用来确定请求应缓存多长时间的Cache-Control头部。对于后续请求,结果将直接从CDN缓存中提供。与Apollo Server的配合的CDN特别强大,因为GraphQL操作可以缩短并以HTTP GET请求发送。

第1步:向GraphQL模式添加缓存提示

将缓存提示作为指令添加到,使Apollo Server知道哪些和类型是可以缓存的以及缓存多长时间。例如,此模式指示应将所有返回Author的字段缓存60秒,将posts字段自身缓存180秒:

type Author @cacheControl(maxAge: 60) {
id: Int
firstName: String
lastName: String
posts: [Post] @cacheControl(maxAge: 180)
}

要了解如何定义@cacheControl指令,请在内部动态指定提示,为所有字段设置默认maxAge,并且只为特定用户缓存字段(使CDN忽略这些字段),请参见缓存

例如,要设置非0的默认最大年龄,您可以在Apollo Server构造函数中包含cacheControl

import { ApolloServerPluginCacheControl } from '@apollo/server/plugin/cacheControl';
const server = new ApolloServer({
typeDefs,
resolvers,
// The max age is calculated in seconds
plugins: [ApolloServerPluginCacheControl({ defaultMaxAge: 5 })],
});

完成此步骤后,Apollo Server将为完全可缓存的响应提供HTTP Cache-Control头信息,这样Apollo Server前的任何CDN都知道哪些响应可以缓存以及缓存多久。Apollo Server会检查包含非零maxAge的数据的响应用户是否未被缓存;该头信息会引用整个响应的最小maxAge值,除非某些数据被标记为scope: PRIVATE。要观察此头信息,请使用任何浏览器的网络标签页在开发工具中进行查看。

步骤 2:启用自动持久查询

通常,GraphQL请求是大的POST请求,而大多数CDN只会缓存GET请求。另外,通常情况下,GET请求效果最佳,当URL尺寸有限时。意味着通过网络发送的是短哈希而不是完整的查询,并且Apollo Client可以配置为对这些哈希查询使用GET请求。

要实现这一点,更新客户端代码。在HTTP链接之前将持久查询链接添加到Apollo Client构造函数中:

import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
import { createPersistedQueryLink } from '@apollo/client/link/persisted-queries';
import { sha256 } from 'crypto-hash';
const link = createPersistedQueryLink({
sha256,
useGETForHashedQueries: true,
}).concat(new HttpLink({ uri: '/graphql' }));
const client = new ApolloClient({
cache: new InMemoryCache(),
link,
});

如果您在本地测试,请确保包含完整的URI,包括端口号。例如:uri: "https://127.0.0.1:4000/graphql"

请确保包含useGETForHashedQueries: true。请注意,客户端仍然会使用POST请求进行mutations操作,因为通常最好不要对非幂等操作使用GET请求。

正确配置后,浏览器的开发工具应该验证查询现在被发送为GET请求,并接收到适当的Cache-Control响应头信息。

步骤 3:配置CDN

具体工作方式取决于您选择哪个CDN。配置您的CDN向 Apollo Server 发送请求。某些CDN可能需要特别配置以遵守源Cache-Control头;例如,以下是 Akamai关于该设置的文档。如果一切正常,可缓存的查询现在应该由CDN保存。

请注意,由CDN直接提供的请求将不会显示在Studio仪表板上。

缓存配置

默认情况下, Apollo Server 在其本地内存缓存中存储其 APQ 注册表。如果您将不同的 cache 作为顶级选项传递给 ApolloServer 构造函数,Apollo Server 则使用该缓存。

您还可以指定一个 专门用于 APQ 注册表的缓存。要做到这一点,将您的首选缓存类的实例作为 cache 选项提供给 ApolloServer 构造函数,并嵌套在 persistedQueries 选项对象中。该 persistedQueries.cache 选项是一个 KeyValueCache,它接受与 Apollo Server 的 Apollo Server's cache 对象相同的配置选项(也是一个 KeyValueCache)。

有关如何配置内存缓存、设置外部缓存或编写自己的缓存实现的信息,请参阅 配置缓存后端

调整缓存时间到生存期(TTL)

缓存时间到生存期(TTL)值决定了已注册的 APQ 在缓存中保持多长时间。如果缓存的查询的TTL过期并被清除,则在下一次客户端发出时重新注册。

Apollo Server's 默认的内存存储不指定 的 TTL(APQ 存在于缓存中,直到被缓存的标准驱逐策略覆盖)。对于所有其他支持的存储,默认TTL为300秒。您可以通过设置 ttl 属性来覆盖或禁用此值,单位是秒:

const server = new ApolloServer({
typeDefs,
resolvers,
persistedQueries: {
ttl: 900, // 15 minutes
},
});

要完全禁用TTL,将 ttl 的值指定为 null

const server = new ApolloServer({
typeDefs,
resolvers,
persistedQueries: {
ttl: null,
},
});

与内存缓存默认行为一样,这会使得 APQs 保留在缓存中,直到被缓存的标准驱逐策略覆盖。

禁用APQ

您可以完全禁用 APQ 通过在 ApolloServer 构造函数选项中将 persistedQueries 属性设置为 false 来实现:

const server = new ApolloServer({
typeDefs,
resolvers,
persistedQueries: false,
});
上一页
缓存后端
下一页
认证
评分文章评分Edit on GitHubEdit论坛加入Discord

©2024Apollo Graph Inc.,经营品牌Apollo GraphQL。

隐私政策

公司