首页
/ GraphQL Yoga 自动持久化查询(APQ)功能详解

GraphQL Yoga 自动持久化查询(APQ)功能详解

2025-07-07 01:55:41作者:裴麒琰

什么是自动持久化查询

自动持久化查询(Automatic Persisted Queries,简称APQ)是一种优化GraphQL网络传输的协议,它的核心目的是减少重复发送相同GraphQL文档到服务器的开销。在GraphQL Yoga中,APQ功能通过专门的插件实现,遵循Apollo的APQ规范。

工作原理

APQ的工作机制分为两个阶段:

  1. 注册阶段:客户端首次发送完整的GraphQL查询时,服务器会计算该查询的SHA256哈希值,并将查询内容存储在缓存中
  2. 执行阶段:后续请求只需发送哈希值,服务器根据哈希值从缓存中获取完整的查询内容执行

这种机制特别适用于查询文档较大的场景,能显著减少客户端到服务器的上行流量。

安全注意事项

需要特别注意的是:

  • APQ仅用于优化网络性能,不提供任何安全功能
  • 潜在的不良行为者可能通过大量注册持久化查询来发起资源消耗攻击
  • 如需限制可执行的GraphQL操作,应使用持久化操作功能而非APQ

安装与快速开始

安装插件

npm install @graphql-yoga/plugin-apq

基础配置

import { createServer } from 'node:http'
import { createSchema, createYoga } from 'graphql-yoga'
import { useAPQ } from '@graphql-yoga/plugin-apq'

const yoga = createYoga({
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      type Query {
        hello: String!
      }
    `
  }),
  plugins: [useAPQ()]
})

const server = createServer(yoga)
server.listen(4000, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})

使用示例

  1. 首次请求(注册查询):
curl -X POST -H 'Content-Type: application/json' http://localhost:4000/graphql \
  -d '{"query":"{__typename}","extensions":{"persistedQuery":{"version":1,"sha256Hash":"ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"}}}'
  1. 后续请求(使用哈希值):
curl -X POST -H 'Content-Type: application/json' http://localhost:4000/graphql \
  -d '{"extensions":{"persistedQuery":{"version":1,"sha256Hash":"ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"}}}'

客户端支持

主流GraphQL客户端如Apollo Client和Urql都内置了对APQ的支持,开发者只需按照各自文档进行配置即可。

高级配置

自定义存储

默认使用内存LRU缓存(最多1000条记录),但可以自定义存储:

const store: APQStore = new Map()

const yoga = createYoga({
  // ...其他配置
  plugins: [useAPQ({ store })]
})

对于外部存储(如Redis),建议添加错误处理:

import Keyv from 'keyv'

const store = new Keyv('redis://user:pass@localhost:6379')

useAPQ({
  store: {
    async get(key) {
      try {
        return await store.get(key)
      } catch (e) {
        console.error(`Error while fetching the operation: ${key}`, e)
      }
    },
    async set(key, value) {
      try {
        return await store.set(key, value)
      } catch (e) {
        console.error(`Error while saving the operation: ${key}`, e)
      }
    }
  }
})

错误响应配置

默认情况下,查询未找到或不匹配时会返回包含HTTP状态码的响应。可以强制使用200状态码:

plugins: [
  useAPQ({
    responseConfig: {
      forceStatusCodeOk: true
    }
  })
]

最佳实践

  1. 对于生产环境,建议使用外部存储而非内存存储
  2. 为外部存储添加完善的错误处理
  3. 监控APQ缓存命中率以评估优化效果
  4. 考虑结合持久化操作功能实现更严格的操作控制

通过合理配置APQ,可以在不影响功能的前提下显著提升GraphQL应用的网络性能,特别是在移动网络等带宽受限的场景下效果更为明显。